[dpdk-dev,v5,2/2] examples/ipsec-secgw: add support for inline protocol

Message ID 1513327396-22178-3-git-send-email-anoob.joseph@caviumnetworks.com (mailing list archive)
State Superseded, archived
Delegated to: Pablo de Lara Guarch
Headers

Checks

Context Check Description
ci/checkpatch success coding style OK
ci/Intel-compilation success Compilation OK

Commit Message

Anoob Joseph Dec. 15, 2017, 8:43 a.m. UTC
  Adding support for inline protocol processing

In ingress side, application will receive regular IP packets, without
any IPsec related info. Application will do a selector check (SP-SA
check) by making use of the metadata from the packet. The
device-specific metadata in mbuf would aid in determing the security
session which processed the packet.

In egress side, the plain packet would be submitted to the driver. The
packet will have optional metadata, which could be used to identify the
security session associated with the packet.

Signed-off-by: Anoob Joseph <anoob.joseph@caviumnetworks.com>
---
v5:
* Fixed checkpatch reported warnings

v4:
* Directly using rte_mbuf.udata64 as the metadata from the packet
* Removed usage of rte_security_get_pkt_metadata API

v3:
* Using (void *)userdata instead of 64 bit metadata in conf
* Changes parallel to the change in API

v2:
* Using get_pkt_metadata API instead of get_session & get_cookie APIs

 examples/ipsec-secgw/esp.c         |   6 +-
 examples/ipsec-secgw/ipsec-secgw.c |  42 ++++++++++++-
 examples/ipsec-secgw/ipsec.c       | 121 +++++++++++++++++++++++++++++++------
 3 files changed, 147 insertions(+), 22 deletions(-)
  

Comments

Nélio Laranjeiro Dec. 15, 2017, 9:39 a.m. UTC | #1
Hi Anoob,

On Fri, Dec 15, 2017 at 08:43:16AM +0000, Anoob Joseph wrote:
> Adding support for inline protocol processing
> 
> In ingress side, application will receive regular IP packets, without
> any IPsec related info. Application will do a selector check (SP-SA
> check) by making use of the metadata from the packet. The
> device-specific metadata in mbuf would aid in determing the security
> session which processed the packet.

This means that your devices removes the tunnel header?  What happens
for packets which could not be decrypted correctly, is also the header
removed?
Anyway this description is wrong as it is not true for all inline
devices.

In addition, in ingress, the same result can be archived by using a mark
id to identify the flow and thus its security association.

> In egress side, the plain packet would be submitted to the driver. The
> packet will have optional metadata, which could be used to identify the
> security session associated with the packet.

Not true for all inline devices, some only need the next-proto for the
ESP part.

> Signed-off-by: Anoob Joseph <anoob.joseph@caviumnetworks.com>
> ---
> v5:
> * Fixed checkpatch reported warnings
> 
> v4:
> * Directly using rte_mbuf.udata64 as the metadata from the packet
> * Removed usage of rte_security_get_pkt_metadata API
> 
> v3:
> * Using (void *)userdata instead of 64 bit metadata in conf
> * Changes parallel to the change in API
> 
> v2:
> * Using get_pkt_metadata API instead of get_session & get_cookie APIs
> 
>  examples/ipsec-secgw/esp.c         |   6 +-
>  examples/ipsec-secgw/ipsec-secgw.c |  42 ++++++++++++-
>  examples/ipsec-secgw/ipsec.c       | 121 +++++++++++++++++++++++++++++++------
>  3 files changed, 147 insertions(+), 22 deletions(-)
> 
> diff --git a/examples/ipsec-secgw/esp.c b/examples/ipsec-secgw/esp.c
> index c3efe52..561f873 100644
> --- a/examples/ipsec-secgw/esp.c
> +++ b/examples/ipsec-secgw/esp.c
> @@ -178,7 +178,8 @@ esp_inbound_post(struct rte_mbuf *m, struct ipsec_sa *sa,
>  	RTE_ASSERT(sa != NULL);
>  	RTE_ASSERT(cop != NULL);
>  
> -	if (sa->type == RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO) {
> +	if ((sa->type == RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL) ||
> +			(sa->type == RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO)) {
>  		if (m->ol_flags & PKT_RX_SEC_OFFLOAD) {
>  			if (m->ol_flags & PKT_RX_SEC_OFFLOAD_FAILED)
>  				cop->status = RTE_CRYPTO_OP_STATUS_ERROR;
> @@ -474,7 +475,8 @@ esp_outbound_post(struct rte_mbuf *m,
>  	RTE_ASSERT(m != NULL);
>  	RTE_ASSERT(sa != NULL);
>  
> -	if (sa->type == RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO) {
> +	if ((sa->type == RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL) ||
> +			(sa->type == RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO)) {
>  		m->ol_flags |= PKT_TX_SEC_OFFLOAD;
>  	} else {
>  		RTE_ASSERT(cop != NULL);
> diff --git a/examples/ipsec-secgw/ipsec-secgw.c b/examples/ipsec-secgw/ipsec-secgw.c
> index c98454a..8254056 100644
> --- a/examples/ipsec-secgw/ipsec-secgw.c
> +++ b/examples/ipsec-secgw/ipsec-secgw.c
> @@ -265,6 +265,40 @@ prepare_one_packet(struct rte_mbuf *pkt, struct ipsec_traffic *t)
>  		RTE_LOG(ERR, IPSEC, "Unsupported packet type\n");
>  		rte_pktmbuf_free(pkt);
>  	}
> +
> +	/* Check if the packet has been processed inline. For inline protocol
> +	 * processed packets, the metadata in the mbuf can be used to identify
> +	 * the security processing done on the packet. The metadata will be
> +	 * used to retrieve the application registered userdata associated
> +	 * with the security session.
> +	 */
> +
> +	if (pkt->ol_flags & PKT_RX_SEC_OFFLOAD) {
> +		struct ipsec_sa *sa;
> +		struct ipsec_mbuf_metadata *priv;
> +		struct rte_security_ctx *ctx = (struct rte_security_ctx *)
> +						rte_eth_dev_get_sec_ctx(
> +						pkt->port);
> +
> +		/* Retrieve the userdata registered. Here, the userdata
> +		 * registered is the SA pointer.
> +		 */
> +
> +		sa = (struct ipsec_sa *)
> +				rte_security_get_userdata(ctx, pkt->udata64);
> +
> +		if (sa == NULL) {
> +			/* userdata could not be retrieved */
> +			return;
> +		}
> +
> +		/* Save SA as priv member in mbuf. This will be used in the
> +		 * IPsec selector(SP-SA) check.
> +		 */
> +
> +		priv = get_priv(pkt);
> +		priv->sa = sa;
> +	}

You must verify the function exists on all drivers, those who don't
support such userdata to be inserted won't implement it.

What happens on security session where the application don't set such
information?  How the application knows the pointer is set correctly?

>  }
>  
>  static inline void
> @@ -401,11 +435,17 @@ inbound_sp_sa(struct sp_ctx *sp, struct sa_ctx *sa, struct traffic_type *ip,
>  			ip->pkts[j++] = m;
>  			continue;
>  		}
> -		if (res & DISCARD || i < lim) {
> +		if (res & DISCARD) {
>  			rte_pktmbuf_free(m);
>  			continue;
>  		}
> +
>  		/* Only check SPI match for processed IPSec packets */
> +		if (i < lim && ((m->ol_flags & PKT_RX_SEC_OFFLOAD) == 0)) {
> +			rte_pktmbuf_free(m);
> +			continue;
> +		}
> +
>  		sa_idx = ip->res[i] & PROTECT_MASK;
>  		if (sa_idx == 0 || !inbound_sa_check(sa, m, sa_idx)) {
>  			rte_pktmbuf_free(m);
> diff --git a/examples/ipsec-secgw/ipsec.c b/examples/ipsec-secgw/ipsec.c
> index 70ed227..bd68ec6 100644
> --- a/examples/ipsec-secgw/ipsec.c
> +++ b/examples/ipsec-secgw/ipsec.c
> @@ -46,6 +46,27 @@
>  #include "ipsec.h"
>  #include "esp.h"
>  
> +static inline void
> +set_ipsec_conf(struct ipsec_sa *sa, struct rte_security_ipsec_xform *ipsec)
> +{
> +	if (ipsec->mode == RTE_SECURITY_IPSEC_SA_MODE_TUNNEL) {
> +		struct rte_security_ipsec_tunnel_param *tunnel =
> +				&ipsec->tunnel;
> +		if (sa->flags == IP4_TUNNEL) {
> +			tunnel->type =
> +				RTE_SECURITY_IPSEC_TUNNEL_IPV4;
> +			tunnel->ipv4.ttl = IPDEFTTL;
> +
> +			memcpy((uint8_t *)&tunnel->ipv4.src_ip,
> +				(uint8_t *)&sa->src.ip.ip4, 4);
> +
> +			memcpy((uint8_t *)&tunnel->ipv4.dst_ip,
> +				(uint8_t *)&sa->dst.ip.ip4, 4);
> +		}
> +		/* TODO support for Transport and IPV6 tunnel */
> +	}
> +}
> +
>  static inline int
>  create_session(struct ipsec_ctx *ipsec_ctx, struct ipsec_sa *sa)
>  {
> @@ -95,7 +116,8 @@ create_session(struct ipsec_ctx *ipsec_ctx, struct ipsec_sa *sa)
>  					RTE_SECURITY_IPSEC_SA_MODE_TUNNEL :
>  					RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT,
>  			} },
> -			.crypto_xform = sa->xforms
> +			.crypto_xform = sa->xforms,
> +			.userdata = NULL,
>  
>  		};
>  
> @@ -104,23 +126,8 @@ create_session(struct ipsec_ctx *ipsec_ctx, struct ipsec_sa *sa)
>  							rte_cryptodev_get_sec_ctx(
>  							ipsec_ctx->tbl[cdev_id_qp].id);
>  
> -			if (sess_conf.ipsec.mode ==
> -					RTE_SECURITY_IPSEC_SA_MODE_TUNNEL) {
> -				struct rte_security_ipsec_tunnel_param *tunnel =
> -						&sess_conf.ipsec.tunnel;
> -				if (sa->flags == IP4_TUNNEL) {
> -					tunnel->type =
> -						RTE_SECURITY_IPSEC_TUNNEL_IPV4;
> -					tunnel->ipv4.ttl = IPDEFTTL;
> -
> -					memcpy((uint8_t *)&tunnel->ipv4.src_ip,
> -						(uint8_t *)&sa->src.ip.ip4, 4);
> -
> -					memcpy((uint8_t *)&tunnel->ipv4.dst_ip,
> -						(uint8_t *)&sa->dst.ip.ip4, 4);
> -				}
> -				/* TODO support for Transport and IPV6 tunnel */
> -			}
> +			/* Set IPsec parameters in conf */
> +			set_ipsec_conf(sa, &(sess_conf.ipsec));
>  
>  			sa->sec_session = rte_security_session_create(ctx,
>  					&sess_conf, ipsec_ctx->session_pool);
> @@ -206,6 +213,70 @@ create_session(struct ipsec_ctx *ipsec_ctx, struct ipsec_sa *sa)
>  					err.message);
>  				return -1;
>  			}
> +		} else if (sa->type ==
> +				RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL) {
> +			struct rte_security_ctx *ctx =
> +					(struct rte_security_ctx *)
> +					rte_eth_dev_get_sec_ctx(sa->portid);
> +			const struct rte_security_capability *sec_cap;
> +
> +			if (ctx == NULL) {
> +				RTE_LOG(ERR, IPSEC,
> +				"Ethernet device doesn't have security features registered\n");
> +				return -1;
> +			}
> +
> +			/* Set IPsec parameters in conf */
> +			set_ipsec_conf(sa, &(sess_conf.ipsec));
> +
> +			/* Save SA as userdata for the security session. When
> +			 * the packet is received, this userdata will be
> +			 * retrieved using the metadata from the packet.
> +			 *
> +			 * This is required only for inbound SAs.
> +			 */

Again not true for all inline devices.

> +
> +			if (sa->direction == RTE_SECURITY_IPSEC_SA_DIR_INGRESS)
> +				sess_conf.userdata = (void *) sa;
> +
> +			sa->sec_session = rte_security_session_create(ctx,
> +					&sess_conf, ipsec_ctx->session_pool);
> +			if (sa->sec_session == NULL) {
> +				RTE_LOG(ERR, IPSEC,
> +				"SEC Session init failed: err: %d\n", ret);
> +				return -1;
> +			}
> +
> +			sec_cap = rte_security_capabilities_get(ctx);
> +
> +			if (sec_cap == NULL) {
> +				RTE_LOG(ERR, IPSEC,
> +				"No capabilities registered\n");
> +				return -1;
> +			}
> +
> +			/* iterate until ESP tunnel*/
> +			while (sec_cap->action !=
> +					RTE_SECURITY_ACTION_TYPE_NONE) {
> +
> +				if (sec_cap->action == sa->type &&
> +				    sec_cap->protocol ==
> +					RTE_SECURITY_PROTOCOL_IPSEC &&
> +				    sec_cap->ipsec.mode ==
> +					RTE_SECURITY_IPSEC_SA_MODE_TUNNEL &&
> +				    sec_cap->ipsec.direction == sa->direction)
> +					break;
> +				sec_cap++;
> +			}
> +
> +			if (sec_cap->action == RTE_SECURITY_ACTION_TYPE_NONE) {
> +				RTE_LOG(ERR, IPSEC,
> +				"No suitable security capability found\n");
> +				return -1;
> +			}
> +
> +			sa->ol_flags = sec_cap->ol_flags;
> +			sa->security_ctx = ctx;
>  		}
>  	} else {
>  		sa->crypto_session = rte_cryptodev_sym_session_create(
> @@ -323,7 +394,19 @@ ipsec_enqueue(ipsec_xform_fn xform_func, struct ipsec_ctx *ipsec_ctx,
>  			}
>  			break;
>  		case RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL:
> -			break;
> +			if ((unlikely(sa->sec_session == NULL)) &&
> +					create_session(ipsec_ctx, sa)) {
> +				rte_pktmbuf_free(pkts[i]);
> +				continue;
> +			}
> +
> +			cqp = &ipsec_ctx->tbl[sa->cdev_id_qp];
> +			cqp->ol_pkts[cqp->ol_pkts_cnt++] = pkts[i];
> +			if (sa->ol_flags & RTE_SECURITY_TX_OLOAD_NEED_MDATA)
> +				rte_security_set_pkt_metadata(
> +						sa->security_ctx,
> +						sa->sec_session, pkts[i], NULL);
> +			continue;
>  		case RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO:
>  			priv->cop.type = RTE_CRYPTO_OP_TYPE_SYMMETRIC;
>  			priv->cop.status = RTE_CRYPTO_OP_STATUS_NOT_PROCESSED;
> -- 
> 2.7.4
> 

Thanks,
  
Akhil Goyal Dec. 15, 2017, 10:04 a.m. UTC | #2
On 12/15/2017 2:13 PM, Anoob Joseph wrote:
> Adding support for inline protocol processing
> 
> In ingress side, application will receive regular IP packets, without
> any IPsec related info. Application will do a selector check (SP-SA
> check) by making use of the metadata from the packet. The
> device-specific metadata in mbuf would aid in determing the security
> session which processed the packet.
> 
> In egress side, the plain packet would be submitted to the driver. The
> packet will have optional metadata, which could be used to identify the
> security session associated with the packet.
> 
> Signed-off-by: Anoob Joseph <anoob.joseph@caviumnetworks.com>
> ---
> v5:
> * Fixed checkpatch reported warnings
> 
> v4:
> * Directly using rte_mbuf.udata64 as the metadata from the packet
> * Removed usage of rte_security_get_pkt_metadata API
> 
> v3:
> * Using (void *)userdata instead of 64 bit metadata in conf
> * Changes parallel to the change in API
> 
> v2:
> * Using get_pkt_metadata API instead of get_session & get_cookie APIs
> 
>   examples/ipsec-secgw/esp.c         |   6 +-
>   examples/ipsec-secgw/ipsec-secgw.c |  42 ++++++++++++-
>   examples/ipsec-secgw/ipsec.c       | 121 +++++++++++++++++++++++++++++++------
>   3 files changed, 147 insertions(+), 22 deletions(-)
> 
> diff --git a/examples/ipsec-secgw/esp.c b/examples/ipsec-secgw/esp.c
> index c3efe52..561f873 100644
> --- a/examples/ipsec-secgw/esp.c
> +++ b/examples/ipsec-secgw/esp.c
> @@ -178,7 +178,8 @@ esp_inbound_post(struct rte_mbuf *m, struct ipsec_sa *sa,
>   	RTE_ASSERT(sa != NULL);
>   	RTE_ASSERT(cop != NULL);
>   
> -	if (sa->type == RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO) {
> +	if ((sa->type == RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL) ||
> +			(sa->type == RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO)) {
>   		if (m->ol_flags & PKT_RX_SEC_OFFLOAD) {
>   			if (m->ol_flags & PKT_RX_SEC_OFFLOAD_FAILED)
>   				cop->status = RTE_CRYPTO_OP_STATUS_ERROR;
> @@ -474,7 +475,8 @@ esp_outbound_post(struct rte_mbuf *m,
>   	RTE_ASSERT(m != NULL);
>   	RTE_ASSERT(sa != NULL);
>   
> -	if (sa->type == RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO) {
> +	if ((sa->type == RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL) ||
> +			(sa->type == RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO)) {
>   		m->ol_flags |= PKT_TX_SEC_OFFLOAD;
>   	} else {
>   		RTE_ASSERT(cop != NULL);
> diff --git a/examples/ipsec-secgw/ipsec-secgw.c b/examples/ipsec-secgw/ipsec-secgw.c
> index c98454a..8254056 100644
> --- a/examples/ipsec-secgw/ipsec-secgw.c
> +++ b/examples/ipsec-secgw/ipsec-secgw.c
> @@ -265,6 +265,40 @@ prepare_one_packet(struct rte_mbuf *pkt, struct ipsec_traffic *t)
>   		RTE_LOG(ERR, IPSEC, "Unsupported packet type\n");
>   		rte_pktmbuf_free(pkt);
>   	}
> +
> +	/* Check if the packet has been processed inline. For inline protocol
> +	 * processed packets, the metadata in the mbuf can be used to identify
> +	 * the security processing done on the packet. The metadata will be
> +	 * used to retrieve the application registered userdata associated
> +	 * with the security session.
> +	 */
> +
> +	if (pkt->ol_flags & PKT_RX_SEC_OFFLOAD) {
> +		struct ipsec_sa *sa;
> +		struct ipsec_mbuf_metadata *priv;
> +		struct rte_security_ctx *ctx = (struct rte_security_ctx *)
> +						rte_eth_dev_get_sec_ctx(
> +						pkt->port);
> +
> +		/* Retrieve the userdata registered. Here, the userdata
> +		 * registered is the SA pointer.
> +		 */
> +
> +		sa = (struct ipsec_sa *)
> +				rte_security_get_userdata(ctx, pkt->udata64);
> +
> +		if (sa == NULL) {
> +			/* userdata could not be retrieved */
Is it mandatory to get userdata for all devices which support 
PKT_RX_SEC_OFFLOAD? I believe not. So you cannot return from here if the 
device does not need userdata.

> +			return;
> +		}
> +
> +		/* Save SA as priv member in mbuf. This will be used in the
> +		 * IPsec selector(SP-SA) check.
> +		 */
> +
> +		priv = get_priv(pkt);
> +		priv->sa = sa;
> +	}
>   }
>   
>   static inline void
> @@ -401,11 +435,17 @@ inbound_sp_sa(struct sp_ctx *sp, struct sa_ctx *sa, struct traffic_type *ip,
>   			ip->pkts[j++] = m;
>   			continue;
>   		}
> -		if (res & DISCARD || i < lim) {
> +		if (res & DISCARD) {
>   			rte_pktmbuf_free(m);
>   			continue;
>   		}
> +
>   		/* Only check SPI match for processed IPSec packets */
> +		if (i < lim && ((m->ol_flags & PKT_RX_SEC_OFFLOAD) == 0)) {
> +			rte_pktmbuf_free(m);
> +			continue;
> +		}
> +
>   		sa_idx = ip->res[i] & PROTECT_MASK;
>   		if (sa_idx == 0 || !inbound_sa_check(sa, m, sa_idx)) {
>   			rte_pktmbuf_free(m);
> diff --git a/examples/ipsec-secgw/ipsec.c b/examples/ipsec-secgw/ipsec.c
> index 70ed227..bd68ec6 100644
> --- a/examples/ipsec-secgw/ipsec.c
> +++ b/examples/ipsec-secgw/ipsec.c
> @@ -46,6 +46,27 @@
>   #include "ipsec.h"
>   #include "esp.h"
>   
> +static inline void
> +set_ipsec_conf(struct ipsec_sa *sa, struct rte_security_ipsec_xform *ipsec)
> +{
> +	if (ipsec->mode == RTE_SECURITY_IPSEC_SA_MODE_TUNNEL) {
> +		struct rte_security_ipsec_tunnel_param *tunnel =
> +				&ipsec->tunnel;
> +		if (sa->flags == IP4_TUNNEL) {
> +			tunnel->type =
> +				RTE_SECURITY_IPSEC_TUNNEL_IPV4;
> +			tunnel->ipv4.ttl = IPDEFTTL;
> +
> +			memcpy((uint8_t *)&tunnel->ipv4.src_ip,
> +				(uint8_t *)&sa->src.ip.ip4, 4);
> +
> +			memcpy((uint8_t *)&tunnel->ipv4.dst_ip,
> +				(uint8_t *)&sa->dst.ip.ip4, 4);
> +		}
> +		/* TODO support for Transport and IPV6 tunnel */
> +	}
> +}
> +
>   static inline int
>   create_session(struct ipsec_ctx *ipsec_ctx, struct ipsec_sa *sa)
>   {
> @@ -95,7 +116,8 @@ create_session(struct ipsec_ctx *ipsec_ctx, struct ipsec_sa *sa)
>   					RTE_SECURITY_IPSEC_SA_MODE_TUNNEL :
>   					RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT,
>   			} },
> -			.crypto_xform = sa->xforms
> +			.crypto_xform = sa->xforms,
> +			.userdata = NULL,
>   
>   		};
>   
> @@ -104,23 +126,8 @@ create_session(struct ipsec_ctx *ipsec_ctx, struct ipsec_sa *sa)
>   							rte_cryptodev_get_sec_ctx(
>   							ipsec_ctx->tbl[cdev_id_qp].id);
>   
> -			if (sess_conf.ipsec.mode ==
> -					RTE_SECURITY_IPSEC_SA_MODE_TUNNEL) {
> -				struct rte_security_ipsec_tunnel_param *tunnel =
> -						&sess_conf.ipsec.tunnel;
> -				if (sa->flags == IP4_TUNNEL) {
> -					tunnel->type =
> -						RTE_SECURITY_IPSEC_TUNNEL_IPV4;
> -					tunnel->ipv4.ttl = IPDEFTTL;
> -
> -					memcpy((uint8_t *)&tunnel->ipv4.src_ip,
> -						(uint8_t *)&sa->src.ip.ip4, 4);
> -
> -					memcpy((uint8_t *)&tunnel->ipv4.dst_ip,
> -						(uint8_t *)&sa->dst.ip.ip4, 4);
> -				}
> -				/* TODO support for Transport and IPV6 tunnel */
> -			}
> +			/* Set IPsec parameters in conf */
> +			set_ipsec_conf(sa, &(sess_conf.ipsec));
>   
>   			sa->sec_session = rte_security_session_create(ctx,
>   					&sess_conf, ipsec_ctx->session_pool);
> @@ -206,6 +213,70 @@ create_session(struct ipsec_ctx *ipsec_ctx, struct ipsec_sa *sa)
>   					err.message);
>   				return -1;
>   			}
> +		} else if (sa->type ==
> +				RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL) {
> +			struct rte_security_ctx *ctx =
> +					(struct rte_security_ctx *)
> +					rte_eth_dev_get_sec_ctx(sa->portid);
> +			const struct rte_security_capability *sec_cap;
> +
> +			if (ctx == NULL) {
> +				RTE_LOG(ERR, IPSEC,
> +				"Ethernet device doesn't have security features registered\n");
> +				return -1;
> +			}
> +
> +			/* Set IPsec parameters in conf */
> +			set_ipsec_conf(sa, &(sess_conf.ipsec));
> +
> +			/* Save SA as userdata for the security session. When
> +			 * the packet is received, this userdata will be
> +			 * retrieved using the metadata from the packet.
> +			 *
> +			 * This is required only for inbound SAs.
> +			 */
> +
> +			if (sa->direction == RTE_SECURITY_IPSEC_SA_DIR_INGRESS)
> +				sess_conf.userdata = (void *) sa;
> +
> +			sa->sec_session = rte_security_session_create(ctx,
> +					&sess_conf, ipsec_ctx->session_pool);
> +			if (sa->sec_session == NULL) {
> +				RTE_LOG(ERR, IPSEC,
> +				"SEC Session init failed: err: %d\n", ret);
> +				return -1;
> +			}
> +
> +			sec_cap = rte_security_capabilities_get(ctx);
> +
> +			if (sec_cap == NULL) {
> +				RTE_LOG(ERR, IPSEC,
> +				"No capabilities registered\n");
> +				return -1;
> +			}
> +
> +			/* iterate until ESP tunnel*/
> +			while (sec_cap->action !=
> +					RTE_SECURITY_ACTION_TYPE_NONE) {
> +
> +				if (sec_cap->action == sa->type &&
> +				    sec_cap->protocol ==
> +					RTE_SECURITY_PROTOCOL_IPSEC &&
> +				    sec_cap->ipsec.mode ==
> +					RTE_SECURITY_IPSEC_SA_MODE_TUNNEL &&
> +				    sec_cap->ipsec.direction == sa->direction)
> +					break;
> +				sec_cap++;
> +			}
> +
> +			if (sec_cap->action == RTE_SECURITY_ACTION_TYPE_NONE) {
> +				RTE_LOG(ERR, IPSEC,
> +				"No suitable security capability found\n");
> +				return -1;
> +			}
> +
> +			sa->ol_flags = sec_cap->ol_flags;
> +			sa->security_ctx = ctx;
>   		}
>   	} else {
>   		sa->crypto_session = rte_cryptodev_sym_session_create(
> @@ -323,7 +394,19 @@ ipsec_enqueue(ipsec_xform_fn xform_func, struct ipsec_ctx *ipsec_ctx,
>   			}
>   			break;
>   		case RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL:
> -			break;
> +			if ((unlikely(sa->sec_session == NULL)) &&
> +					create_session(ipsec_ctx, sa)) {
> +				rte_pktmbuf_free(pkts[i]);
> +				continue;
> +			}
> +
> +			cqp = &ipsec_ctx->tbl[sa->cdev_id_qp];
> +			cqp->ol_pkts[cqp->ol_pkts_cnt++] = pkts[i];
> +			if (sa->ol_flags & RTE_SECURITY_TX_OLOAD_NEED_MDATA)
> +				rte_security_set_pkt_metadata(
> +						sa->security_ctx,
> +						sa->sec_session, pkts[i], NULL);
> +			continue;
>   		case RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO:
>   			priv->cop.type = RTE_CRYPTO_OP_TYPE_SYMMETRIC;
>   			priv->cop.status = RTE_CRYPTO_OP_STATUS_NOT_PROCESSED;
>
  
Anoob Joseph Dec. 15, 2017, 11:03 a.m. UTC | #3
Hi Nelio,


On 12/15/2017 03:09 PM, Nelio Laranjeiro wrote:
> Hi Anoob,
>
> On Fri, Dec 15, 2017 at 08:43:16AM +0000, Anoob Joseph wrote:
>> Adding support for inline protocol processing
>>
>> In ingress side, application will receive regular IP packets, without
>> any IPsec related info. Application will do a selector check (SP-SA
>> check) by making use of the metadata from the packet. The
>> device-specific metadata in mbuf would aid in determing the security
>> session which processed the packet.
> This means that your devices removes the tunnel header?  What happens
> for packets which could not be decrypted correctly, is also the header
> removed?
> Anyway this description is wrong as it is not true for all inline
> devices.
This is particularly for inline protocol processed packets. For inline 
crypto, tunnel headers will be present, but for inline protocol tunnel 
headers need not be present.
>
> In addition, in ingress, the same result can be archived by using a mark
> id to identify the flow and thus its security association.
>
>> In egress side, the plain packet would be submitted to the driver. The
>> packet will have optional metadata, which could be used to identify the
>> security session associated with the packet.
> Not true for all inline devices, some only need the next-proto for the
> ESP part.
This is more or less existing behavior for inline crypto. Inline 
protocol shares most of it's behavior with inline crypto.
>
>> Signed-off-by: Anoob Joseph <anoob.joseph@caviumnetworks.com>
>> ---
>> v5:
>> * Fixed checkpatch reported warnings
>>
>> v4:
>> * Directly using rte_mbuf.udata64 as the metadata from the packet
>> * Removed usage of rte_security_get_pkt_metadata API
>>
>> v3:
>> * Using (void *)userdata instead of 64 bit metadata in conf
>> * Changes parallel to the change in API
>>
>> v2:
>> * Using get_pkt_metadata API instead of get_session & get_cookie APIs
>>
>>   examples/ipsec-secgw/esp.c         |   6 +-
>>   examples/ipsec-secgw/ipsec-secgw.c |  42 ++++++++++++-
>>   examples/ipsec-secgw/ipsec.c       | 121 +++++++++++++++++++++++++++++++------
>>   3 files changed, 147 insertions(+), 22 deletions(-)
>>
>> diff --git a/examples/ipsec-secgw/esp.c b/examples/ipsec-secgw/esp.c
>> index c3efe52..561f873 100644
>> --- a/examples/ipsec-secgw/esp.c
>> +++ b/examples/ipsec-secgw/esp.c
>> @@ -178,7 +178,8 @@ esp_inbound_post(struct rte_mbuf *m, struct ipsec_sa *sa,
>>   	RTE_ASSERT(sa != NULL);
>>   	RTE_ASSERT(cop != NULL);
>>   
>> -	if (sa->type == RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO) {
>> +	if ((sa->type == RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL) ||
>> +			(sa->type == RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO)) {
>>   		if (m->ol_flags & PKT_RX_SEC_OFFLOAD) {
>>   			if (m->ol_flags & PKT_RX_SEC_OFFLOAD_FAILED)
>>   				cop->status = RTE_CRYPTO_OP_STATUS_ERROR;
>> @@ -474,7 +475,8 @@ esp_outbound_post(struct rte_mbuf *m,
>>   	RTE_ASSERT(m != NULL);
>>   	RTE_ASSERT(sa != NULL);
>>   
>> -	if (sa->type == RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO) {
>> +	if ((sa->type == RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL) ||
>> +			(sa->type == RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO)) {
>>   		m->ol_flags |= PKT_TX_SEC_OFFLOAD;
>>   	} else {
>>   		RTE_ASSERT(cop != NULL);
>> diff --git a/examples/ipsec-secgw/ipsec-secgw.c b/examples/ipsec-secgw/ipsec-secgw.c
>> index c98454a..8254056 100644
>> --- a/examples/ipsec-secgw/ipsec-secgw.c
>> +++ b/examples/ipsec-secgw/ipsec-secgw.c
>> @@ -265,6 +265,40 @@ prepare_one_packet(struct rte_mbuf *pkt, struct ipsec_traffic *t)
>>   		RTE_LOG(ERR, IPSEC, "Unsupported packet type\n");
>>   		rte_pktmbuf_free(pkt);
>>   	}
>> +
>> +	/* Check if the packet has been processed inline. For inline protocol
>> +	 * processed packets, the metadata in the mbuf can be used to identify
>> +	 * the security processing done on the packet. The metadata will be
>> +	 * used to retrieve the application registered userdata associated
>> +	 * with the security session.
>> +	 */
>> +
>> +	if (pkt->ol_flags & PKT_RX_SEC_OFFLOAD) {
>> +		struct ipsec_sa *sa;
>> +		struct ipsec_mbuf_metadata *priv;
>> +		struct rte_security_ctx *ctx = (struct rte_security_ctx *)
>> +						rte_eth_dev_get_sec_ctx(
>> +						pkt->port);
>> +
>> +		/* Retrieve the userdata registered. Here, the userdata
>> +		 * registered is the SA pointer.
>> +		 */
>> +
>> +		sa = (struct ipsec_sa *)
>> +				rte_security_get_userdata(ctx, pkt->udata64);
>> +
>> +		if (sa == NULL) {
>> +			/* userdata could not be retrieved */
>> +			return;
>> +		}
>> +
>> +		/* Save SA as priv member in mbuf. This will be used in the
>> +		 * IPsec selector(SP-SA) check.
>> +		 */
>> +
>> +		priv = get_priv(pkt);
>> +		priv->sa = sa;
>> +	}
> You must verify the function exists on all drivers, those who don't
> support such userdata to be inserted won't implement it.
That check is there in library. It will return NULL and then the 
function would exit
>
> What happens on security session where the application don't set such
> information?  How the application knows the pointer is set correctly?
Application is the one who sets and gets the pointer. If application 
doesn't set it correctly, application will not able to use it. If 
application doesn't set this, for inline protocol, the application won't 
have any information which it can use to identify the security 
processing done.
>
>>   }
>>   
>>   static inline void
>> @@ -401,11 +435,17 @@ inbound_sp_sa(struct sp_ctx *sp, struct sa_ctx *sa, struct traffic_type *ip,
>>   			ip->pkts[j++] = m;
>>   			continue;
>>   		}
>> -		if (res & DISCARD || i < lim) {
>> +		if (res & DISCARD) {
>>   			rte_pktmbuf_free(m);
>>   			continue;
>>   		}
>> +
>>   		/* Only check SPI match for processed IPSec packets */
>> +		if (i < lim && ((m->ol_flags & PKT_RX_SEC_OFFLOAD) == 0)) {
>> +			rte_pktmbuf_free(m);
>> +			continue;
>> +		}
>> +
>>   		sa_idx = ip->res[i] & PROTECT_MASK;
>>   		if (sa_idx == 0 || !inbound_sa_check(sa, m, sa_idx)) {
>>   			rte_pktmbuf_free(m);
>> diff --git a/examples/ipsec-secgw/ipsec.c b/examples/ipsec-secgw/ipsec.c
>> index 70ed227..bd68ec6 100644
>> --- a/examples/ipsec-secgw/ipsec.c
>> +++ b/examples/ipsec-secgw/ipsec.c
>> @@ -46,6 +46,27 @@
>>   #include "ipsec.h"
>>   #include "esp.h"
>>   
>> +static inline void
>> +set_ipsec_conf(struct ipsec_sa *sa, struct rte_security_ipsec_xform *ipsec)
>> +{
>> +	if (ipsec->mode == RTE_SECURITY_IPSEC_SA_MODE_TUNNEL) {
>> +		struct rte_security_ipsec_tunnel_param *tunnel =
>> +				&ipsec->tunnel;
>> +		if (sa->flags == IP4_TUNNEL) {
>> +			tunnel->type =
>> +				RTE_SECURITY_IPSEC_TUNNEL_IPV4;
>> +			tunnel->ipv4.ttl = IPDEFTTL;
>> +
>> +			memcpy((uint8_t *)&tunnel->ipv4.src_ip,
>> +				(uint8_t *)&sa->src.ip.ip4, 4);
>> +
>> +			memcpy((uint8_t *)&tunnel->ipv4.dst_ip,
>> +				(uint8_t *)&sa->dst.ip.ip4, 4);
>> +		}
>> +		/* TODO support for Transport and IPV6 tunnel */
>> +	}
>> +}
>> +
>>   static inline int
>>   create_session(struct ipsec_ctx *ipsec_ctx, struct ipsec_sa *sa)
>>   {
>> @@ -95,7 +116,8 @@ create_session(struct ipsec_ctx *ipsec_ctx, struct ipsec_sa *sa)
>>   					RTE_SECURITY_IPSEC_SA_MODE_TUNNEL :
>>   					RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT,
>>   			} },
>> -			.crypto_xform = sa->xforms
>> +			.crypto_xform = sa->xforms,
>> +			.userdata = NULL,
>>   
>>   		};
>>   
>> @@ -104,23 +126,8 @@ create_session(struct ipsec_ctx *ipsec_ctx, struct ipsec_sa *sa)
>>   							rte_cryptodev_get_sec_ctx(
>>   							ipsec_ctx->tbl[cdev_id_qp].id);
>>   
>> -			if (sess_conf.ipsec.mode ==
>> -					RTE_SECURITY_IPSEC_SA_MODE_TUNNEL) {
>> -				struct rte_security_ipsec_tunnel_param *tunnel =
>> -						&sess_conf.ipsec.tunnel;
>> -				if (sa->flags == IP4_TUNNEL) {
>> -					tunnel->type =
>> -						RTE_SECURITY_IPSEC_TUNNEL_IPV4;
>> -					tunnel->ipv4.ttl = IPDEFTTL;
>> -
>> -					memcpy((uint8_t *)&tunnel->ipv4.src_ip,
>> -						(uint8_t *)&sa->src.ip.ip4, 4);
>> -
>> -					memcpy((uint8_t *)&tunnel->ipv4.dst_ip,
>> -						(uint8_t *)&sa->dst.ip.ip4, 4);
>> -				}
>> -				/* TODO support for Transport and IPV6 tunnel */
>> -			}
>> +			/* Set IPsec parameters in conf */
>> +			set_ipsec_conf(sa, &(sess_conf.ipsec));
>>   
>>   			sa->sec_session = rte_security_session_create(ctx,
>>   					&sess_conf, ipsec_ctx->session_pool);
>> @@ -206,6 +213,70 @@ create_session(struct ipsec_ctx *ipsec_ctx, struct ipsec_sa *sa)
>>   					err.message);
>>   				return -1;
>>   			}
>> +		} else if (sa->type ==
>> +				RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL) {
>> +			struct rte_security_ctx *ctx =
>> +					(struct rte_security_ctx *)
>> +					rte_eth_dev_get_sec_ctx(sa->portid);
>> +			const struct rte_security_capability *sec_cap;
>> +
>> +			if (ctx == NULL) {
>> +				RTE_LOG(ERR, IPSEC,
>> +				"Ethernet device doesn't have security features registered\n");
>> +				return -1;
>> +			}
>> +
>> +			/* Set IPsec parameters in conf */
>> +			set_ipsec_conf(sa, &(sess_conf.ipsec));
>> +
>> +			/* Save SA as userdata for the security session. When
>> +			 * the packet is received, this userdata will be
>> +			 * retrieved using the metadata from the packet.
>> +			 *
>> +			 * This is required only for inbound SAs.
>> +			 */
> Again not true for all inline devices.
Should be valid for all inline protocol devices. May be addition of 
capability would look better?
>
>> +
>> +			if (sa->direction == RTE_SECURITY_IPSEC_SA_DIR_INGRESS)
>> +				sess_conf.userdata = (void *) sa;
>> +
>> +			sa->sec_session = rte_security_session_create(ctx,
>> +					&sess_conf, ipsec_ctx->session_pool);
>> +			if (sa->sec_session == NULL) {
>> +				RTE_LOG(ERR, IPSEC,
>> +				"SEC Session init failed: err: %d\n", ret);
>> +				return -1;
>> +			}
>> +
>> +			sec_cap = rte_security_capabilities_get(ctx);
>> +
>> +			if (sec_cap == NULL) {
>> +				RTE_LOG(ERR, IPSEC,
>> +				"No capabilities registered\n");
>> +				return -1;
>> +			}
>> +
>> +			/* iterate until ESP tunnel*/
>> +			while (sec_cap->action !=
>> +					RTE_SECURITY_ACTION_TYPE_NONE) {
>> +
>> +				if (sec_cap->action == sa->type &&
>> +				    sec_cap->protocol ==
>> +					RTE_SECURITY_PROTOCOL_IPSEC &&
>> +				    sec_cap->ipsec.mode ==
>> +					RTE_SECURITY_IPSEC_SA_MODE_TUNNEL &&
>> +				    sec_cap->ipsec.direction == sa->direction)
>> +					break;
>> +				sec_cap++;
>> +			}
>> +
>> +			if (sec_cap->action == RTE_SECURITY_ACTION_TYPE_NONE) {
>> +				RTE_LOG(ERR, IPSEC,
>> +				"No suitable security capability found\n");
>> +				return -1;
>> +			}
>> +
>> +			sa->ol_flags = sec_cap->ol_flags;
>> +			sa->security_ctx = ctx;
>>   		}
>>   	} else {
>>   		sa->crypto_session = rte_cryptodev_sym_session_create(
>> @@ -323,7 +394,19 @@ ipsec_enqueue(ipsec_xform_fn xform_func, struct ipsec_ctx *ipsec_ctx,
>>   			}
>>   			break;
>>   		case RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL:
>> -			break;
>> +			if ((unlikely(sa->sec_session == NULL)) &&
>> +					create_session(ipsec_ctx, sa)) {
>> +				rte_pktmbuf_free(pkts[i]);
>> +				continue;
>> +			}
>> +
>> +			cqp = &ipsec_ctx->tbl[sa->cdev_id_qp];
>> +			cqp->ol_pkts[cqp->ol_pkts_cnt++] = pkts[i];
>> +			if (sa->ol_flags & RTE_SECURITY_TX_OLOAD_NEED_MDATA)
>> +				rte_security_set_pkt_metadata(
>> +						sa->security_ctx,
>> +						sa->sec_session, pkts[i], NULL);
>> +			continue;
>>   		case RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO:
>>   			priv->cop.type = RTE_CRYPTO_OP_TYPE_SYMMETRIC;
>>   			priv->cop.status = RTE_CRYPTO_OP_STATUS_NOT_PROCESSED;
>> -- 
>> 2.7.4
>>
> Thanks,
>
Thanks,
Anoob
  
Anoob Joseph Dec. 15, 2017, 11:16 a.m. UTC | #4
Hi Akhil,


On 12/15/2017 03:34 PM, Akhil Goyal wrote:
> On 12/15/2017 2:13 PM, Anoob Joseph wrote:
>> Adding support for inline protocol processing
>>
>> In ingress side, application will receive regular IP packets, without
>> any IPsec related info. Application will do a selector check (SP-SA
>> check) by making use of the metadata from the packet. The
>> device-specific metadata in mbuf would aid in determing the security
>> session which processed the packet.
>>
>> In egress side, the plain packet would be submitted to the driver. The
>> packet will have optional metadata, which could be used to identify the
>> security session associated with the packet.
>>
>> Signed-off-by: Anoob Joseph <anoob.joseph@caviumnetworks.com>
>> ---
>> v5:
>> * Fixed checkpatch reported warnings
>>
>> v4:
>> * Directly using rte_mbuf.udata64 as the metadata from the packet
>> * Removed usage of rte_security_get_pkt_metadata API
>>
>> v3:
>> * Using (void *)userdata instead of 64 bit metadata in conf
>> * Changes parallel to the change in API
>>
>> v2:
>> * Using get_pkt_metadata API instead of get_session & get_cookie APIs
>>
>>   examples/ipsec-secgw/esp.c         |   6 +-
>>   examples/ipsec-secgw/ipsec-secgw.c |  42 ++++++++++++-
>>   examples/ipsec-secgw/ipsec.c       | 121 
>> +++++++++++++++++++++++++++++++------
>>   3 files changed, 147 insertions(+), 22 deletions(-)
>>
>> diff --git a/examples/ipsec-secgw/esp.c b/examples/ipsec-secgw/esp.c
>> index c3efe52..561f873 100644
>> --- a/examples/ipsec-secgw/esp.c
>> +++ b/examples/ipsec-secgw/esp.c
>> @@ -178,7 +178,8 @@ esp_inbound_post(struct rte_mbuf *m, struct 
>> ipsec_sa *sa,
>>       RTE_ASSERT(sa != NULL);
>>       RTE_ASSERT(cop != NULL);
>>   -    if (sa->type == RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO) {
>> +    if ((sa->type == RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL) ||
>> +            (sa->type == RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO)) {
>>           if (m->ol_flags & PKT_RX_SEC_OFFLOAD) {
>>               if (m->ol_flags & PKT_RX_SEC_OFFLOAD_FAILED)
>>                   cop->status = RTE_CRYPTO_OP_STATUS_ERROR;
>> @@ -474,7 +475,8 @@ esp_outbound_post(struct rte_mbuf *m,
>>       RTE_ASSERT(m != NULL);
>>       RTE_ASSERT(sa != NULL);
>>   -    if (sa->type == RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO) {
>> +    if ((sa->type == RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL) ||
>> +            (sa->type == RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO)) {
>>           m->ol_flags |= PKT_TX_SEC_OFFLOAD;
>>       } else {
>>           RTE_ASSERT(cop != NULL);
>> diff --git a/examples/ipsec-secgw/ipsec-secgw.c 
>> b/examples/ipsec-secgw/ipsec-secgw.c
>> index c98454a..8254056 100644
>> --- a/examples/ipsec-secgw/ipsec-secgw.c
>> +++ b/examples/ipsec-secgw/ipsec-secgw.c
>> @@ -265,6 +265,40 @@ prepare_one_packet(struct rte_mbuf *pkt, struct 
>> ipsec_traffic *t)
>>           RTE_LOG(ERR, IPSEC, "Unsupported packet type\n");
>>           rte_pktmbuf_free(pkt);
>>       }
>> +
>> +    /* Check if the packet has been processed inline. For inline 
>> protocol
>> +     * processed packets, the metadata in the mbuf can be used to 
>> identify
>> +     * the security processing done on the packet. The metadata will be
>> +     * used to retrieve the application registered userdata associated
>> +     * with the security session.
>> +     */
>> +
>> +    if (pkt->ol_flags & PKT_RX_SEC_OFFLOAD) {
>> +        struct ipsec_sa *sa;
>> +        struct ipsec_mbuf_metadata *priv;
>> +        struct rte_security_ctx *ctx = (struct rte_security_ctx *)
>> +                        rte_eth_dev_get_sec_ctx(
>> +                        pkt->port);
>> +
>> +        /* Retrieve the userdata registered. Here, the userdata
>> +         * registered is the SA pointer.
>> +         */
>> +
>> +        sa = (struct ipsec_sa *)
>> +                rte_security_get_userdata(ctx, pkt->udata64);
>> +
>> +        if (sa == NULL) {
>> +            /* userdata could not be retrieved */
> Is it mandatory to get userdata for all devices which support 
> PKT_RX_SEC_OFFLOAD? I believe not. So you cannot return from here if 
> the device does not need userdata.
This code was added in the end. "return" was added because nothing else 
had to be done following this. May be I can make this code block a 
static inline function. Then it won't be misleading.

There is no flag in mbuf to differentiate between inline protocol & 
inline crypto. PKT_RX_SEC_OFFLOAD will denote that inline processing has 
been done, but not which. For inline-crypto, the "priv->sa" field will 
get (over) written, as the SA is identified. Whether inline-crypto would 
need "userdata" is open for discussions. This userdata will be valid 
only if it is set while the security session is created. Right now, we 
set it only for inline-protocol processed ones.
>
>> +            return;
>> +        }
>> +
>> +        /* Save SA as priv member in mbuf. This will be used in the
>> +         * IPsec selector(SP-SA) check.
>> +         */
>> +
>> +        priv = get_priv(pkt);
>> +        priv->sa = sa;
>> +    }
>>   }
>>     static inline void
>> @@ -401,11 +435,17 @@ inbound_sp_sa(struct sp_ctx *sp, struct sa_ctx 
>> *sa, struct traffic_type *ip,
>>               ip->pkts[j++] = m;
>>               continue;
>>           }
>> -        if (res & DISCARD || i < lim) {
>> +        if (res & DISCARD) {
>>               rte_pktmbuf_free(m);
>>               continue;
>>           }
>> +
>>           /* Only check SPI match for processed IPSec packets */
>> +        if (i < lim && ((m->ol_flags & PKT_RX_SEC_OFFLOAD) == 0)) {
>> +            rte_pktmbuf_free(m);
>> +            continue;
>> +        }
>> +
>>           sa_idx = ip->res[i] & PROTECT_MASK;
>>           if (sa_idx == 0 || !inbound_sa_check(sa, m, sa_idx)) {
>>               rte_pktmbuf_free(m);
>> diff --git a/examples/ipsec-secgw/ipsec.c b/examples/ipsec-secgw/ipsec.c
>> index 70ed227..bd68ec6 100644
>> --- a/examples/ipsec-secgw/ipsec.c
>> +++ b/examples/ipsec-secgw/ipsec.c
>> @@ -46,6 +46,27 @@
>>   #include "ipsec.h"
>>   #include "esp.h"
>>   +static inline void
>> +set_ipsec_conf(struct ipsec_sa *sa, struct rte_security_ipsec_xform 
>> *ipsec)
>> +{
>> +    if (ipsec->mode == RTE_SECURITY_IPSEC_SA_MODE_TUNNEL) {
>> +        struct rte_security_ipsec_tunnel_param *tunnel =
>> +                &ipsec->tunnel;
>> +        if (sa->flags == IP4_TUNNEL) {
>> +            tunnel->type =
>> +                RTE_SECURITY_IPSEC_TUNNEL_IPV4;
>> +            tunnel->ipv4.ttl = IPDEFTTL;
>> +
>> +            memcpy((uint8_t *)&tunnel->ipv4.src_ip,
>> +                (uint8_t *)&sa->src.ip.ip4, 4);
>> +
>> +            memcpy((uint8_t *)&tunnel->ipv4.dst_ip,
>> +                (uint8_t *)&sa->dst.ip.ip4, 4);
>> +        }
>> +        /* TODO support for Transport and IPV6 tunnel */
>> +    }
>> +}
>> +
>>   static inline int
>>   create_session(struct ipsec_ctx *ipsec_ctx, struct ipsec_sa *sa)
>>   {
>> @@ -95,7 +116,8 @@ create_session(struct ipsec_ctx *ipsec_ctx, struct 
>> ipsec_sa *sa)
>>                       RTE_SECURITY_IPSEC_SA_MODE_TUNNEL :
>>                       RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT,
>>               } },
>> -            .crypto_xform = sa->xforms
>> +            .crypto_xform = sa->xforms,
>> +            .userdata = NULL,
>>             };
>>   @@ -104,23 +126,8 @@ create_session(struct ipsec_ctx *ipsec_ctx, 
>> struct ipsec_sa *sa)
>>                               rte_cryptodev_get_sec_ctx(
>>                               ipsec_ctx->tbl[cdev_id_qp].id);
>>   -            if (sess_conf.ipsec.mode ==
>> -                    RTE_SECURITY_IPSEC_SA_MODE_TUNNEL) {
>> -                struct rte_security_ipsec_tunnel_param *tunnel =
>> -                        &sess_conf.ipsec.tunnel;
>> -                if (sa->flags == IP4_TUNNEL) {
>> -                    tunnel->type =
>> -                        RTE_SECURITY_IPSEC_TUNNEL_IPV4;
>> -                    tunnel->ipv4.ttl = IPDEFTTL;
>> -
>> -                    memcpy((uint8_t *)&tunnel->ipv4.src_ip,
>> -                        (uint8_t *)&sa->src.ip.ip4, 4);
>> -
>> -                    memcpy((uint8_t *)&tunnel->ipv4.dst_ip,
>> -                        (uint8_t *)&sa->dst.ip.ip4, 4);
>> -                }
>> -                /* TODO support for Transport and IPV6 tunnel */
>> -            }
>> +            /* Set IPsec parameters in conf */
>> +            set_ipsec_conf(sa, &(sess_conf.ipsec));
>>                 sa->sec_session = rte_security_session_create(ctx,
>>                       &sess_conf, ipsec_ctx->session_pool);
>> @@ -206,6 +213,70 @@ create_session(struct ipsec_ctx *ipsec_ctx, 
>> struct ipsec_sa *sa)
>>                       err.message);
>>                   return -1;
>>               }
>> +        } else if (sa->type ==
>> +                RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL) {
>> +            struct rte_security_ctx *ctx =
>> +                    (struct rte_security_ctx *)
>> +                    rte_eth_dev_get_sec_ctx(sa->portid);
>> +            const struct rte_security_capability *sec_cap;
>> +
>> +            if (ctx == NULL) {
>> +                RTE_LOG(ERR, IPSEC,
>> +                "Ethernet device doesn't have security features 
>> registered\n");
>> +                return -1;
>> +            }
>> +
>> +            /* Set IPsec parameters in conf */
>> +            set_ipsec_conf(sa, &(sess_conf.ipsec));
>> +
>> +            /* Save SA as userdata for the security session. When
>> +             * the packet is received, this userdata will be
>> +             * retrieved using the metadata from the packet.
>> +             *
>> +             * This is required only for inbound SAs.
>> +             */
>> +
>> +            if (sa->direction == RTE_SECURITY_IPSEC_SA_DIR_INGRESS)
>> +                sess_conf.userdata = (void *) sa;
>> +
>> +            sa->sec_session = rte_security_session_create(ctx,
>> +                    &sess_conf, ipsec_ctx->session_pool);
>> +            if (sa->sec_session == NULL) {
>> +                RTE_LOG(ERR, IPSEC,
>> +                "SEC Session init failed: err: %d\n", ret);
>> +                return -1;
>> +            }
>> +
>> +            sec_cap = rte_security_capabilities_get(ctx);
>> +
>> +            if (sec_cap == NULL) {
>> +                RTE_LOG(ERR, IPSEC,
>> +                "No capabilities registered\n");
>> +                return -1;
>> +            }
>> +
>> +            /* iterate until ESP tunnel*/
>> +            while (sec_cap->action !=
>> +                    RTE_SECURITY_ACTION_TYPE_NONE) {
>> +
>> +                if (sec_cap->action == sa->type &&
>> +                    sec_cap->protocol ==
>> +                    RTE_SECURITY_PROTOCOL_IPSEC &&
>> +                    sec_cap->ipsec.mode ==
>> +                    RTE_SECURITY_IPSEC_SA_MODE_TUNNEL &&
>> +                    sec_cap->ipsec.direction == sa->direction)
>> +                    break;
>> +                sec_cap++;
>> +            }
>> +
>> +            if (sec_cap->action == RTE_SECURITY_ACTION_TYPE_NONE) {
>> +                RTE_LOG(ERR, IPSEC,
>> +                "No suitable security capability found\n");
>> +                return -1;
>> +            }
>> +
>> +            sa->ol_flags = sec_cap->ol_flags;
>> +            sa->security_ctx = ctx;
>>           }
>>       } else {
>>           sa->crypto_session = rte_cryptodev_sym_session_create(
>> @@ -323,7 +394,19 @@ ipsec_enqueue(ipsec_xform_fn xform_func, struct 
>> ipsec_ctx *ipsec_ctx,
>>               }
>>               break;
>>           case RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL:
>> -            break;
>> +            if ((unlikely(sa->sec_session == NULL)) &&
>> +                    create_session(ipsec_ctx, sa)) {
>> +                rte_pktmbuf_free(pkts[i]);
>> +                continue;
>> +            }
>> +
>> +            cqp = &ipsec_ctx->tbl[sa->cdev_id_qp];
>> +            cqp->ol_pkts[cqp->ol_pkts_cnt++] = pkts[i];
>> +            if (sa->ol_flags & RTE_SECURITY_TX_OLOAD_NEED_MDATA)
>> +                rte_security_set_pkt_metadata(
>> +                        sa->security_ctx,
>> +                        sa->sec_session, pkts[i], NULL);
>> +            continue;
>>           case RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO:
>>               priv->cop.type = RTE_CRYPTO_OP_TYPE_SYMMETRIC;
>>               priv->cop.status = RTE_CRYPTO_OP_STATUS_NOT_PROCESSED;
>>
>
  
Nélio Laranjeiro Dec. 15, 2017, 1:35 p.m. UTC | #5
On Fri, Dec 15, 2017 at 04:33:25PM +0530, Anoob Joseph wrote:
> Hi Nelio,
> 
> 
> On 12/15/2017 03:09 PM, Nelio Laranjeiro wrote:
> > Hi Anoob,
> > 
> > On Fri, Dec 15, 2017 at 08:43:16AM +0000, Anoob Joseph wrote:
> > > Adding support for inline protocol processing
> > > 
> > > In ingress side, application will receive regular IP packets, without
> > > any IPsec related info. Application will do a selector check (SP-SA
> > > check) by making use of the metadata from the packet. The
> > > device-specific metadata in mbuf would aid in determing the security
> > > session which processed the packet.
> > This means that your devices removes the tunnel header?  What happens
> > for packets which could not be decrypted correctly, is also the header
> > removed?
> > Anyway this description is wrong as it is not true for all inline
> > devices.
> This is particularly for inline protocol processed packets. For inline
> crypto, tunnel headers will be present, but for inline protocol tunnel
> headers need not be present.

Ok, my bad, I did not see the RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL
additional flag.

Sorry,

> > In addition, in ingress, the same result can be archived by using a mark
> > id to identify the flow and thus its security association.
> > 
> > > In egress side, the plain packet would be submitted to the driver. The
> > > packet will have optional metadata, which could be used to identify the
> > > security session associated with the packet.
> > Not true for all inline devices, some only need the next-proto for the
> > ESP part.
> This is more or less existing behavior for inline crypto. Inline protocol
> shares most of it's behavior with inline crypto.
> > 
> > > Signed-off-by: Anoob Joseph <anoob.joseph@caviumnetworks.com>
> > > ---
> > > v5:
> > > * Fixed checkpatch reported warnings
> > > 
> > > v4:
> > > * Directly using rte_mbuf.udata64 as the metadata from the packet
> > > * Removed usage of rte_security_get_pkt_metadata API
> > > 
> > > v3:
> > > * Using (void *)userdata instead of 64 bit metadata in conf
> > > * Changes parallel to the change in API
> > > 
> > > v2:
> > > * Using get_pkt_metadata API instead of get_session & get_cookie APIs
> > > 
> > >   examples/ipsec-secgw/esp.c         |   6 +-
> > >   examples/ipsec-secgw/ipsec-secgw.c |  42 ++++++++++++-
> > >   examples/ipsec-secgw/ipsec.c       | 121 +++++++++++++++++++++++++++++++------
> > >   3 files changed, 147 insertions(+), 22 deletions(-)
> > > 
> > > diff --git a/examples/ipsec-secgw/esp.c b/examples/ipsec-secgw/esp.c
> > > index c3efe52..561f873 100644
> > > --- a/examples/ipsec-secgw/esp.c
> > > +++ b/examples/ipsec-secgw/esp.c
> > > @@ -178,7 +178,8 @@ esp_inbound_post(struct rte_mbuf *m, struct ipsec_sa *sa,
> > >   	RTE_ASSERT(sa != NULL);
> > >   	RTE_ASSERT(cop != NULL);
> > > -	if (sa->type == RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO) {
> > > +	if ((sa->type == RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL) ||
> > > +			(sa->type == RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO)) {
> > >   		if (m->ol_flags & PKT_RX_SEC_OFFLOAD) {
> > >   			if (m->ol_flags & PKT_RX_SEC_OFFLOAD_FAILED)
> > >   				cop->status = RTE_CRYPTO_OP_STATUS_ERROR;
> > > @@ -474,7 +475,8 @@ esp_outbound_post(struct rte_mbuf *m,
> > >   	RTE_ASSERT(m != NULL);
> > >   	RTE_ASSERT(sa != NULL);
> > > -	if (sa->type == RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO) {
> > > +	if ((sa->type == RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL) ||
> > > +			(sa->type == RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO)) {
> > >   		m->ol_flags |= PKT_TX_SEC_OFFLOAD;
> > >   	} else {
> > >   		RTE_ASSERT(cop != NULL);
> > > diff --git a/examples/ipsec-secgw/ipsec-secgw.c b/examples/ipsec-secgw/ipsec-secgw.c
> > > index c98454a..8254056 100644
> > > --- a/examples/ipsec-secgw/ipsec-secgw.c
> > > +++ b/examples/ipsec-secgw/ipsec-secgw.c
> > > @@ -265,6 +265,40 @@ prepare_one_packet(struct rte_mbuf *pkt, struct ipsec_traffic *t)
> > >   		RTE_LOG(ERR, IPSEC, "Unsupported packet type\n");
> > >   		rte_pktmbuf_free(pkt);
> > >   	}
> > > +
> > > +	/* Check if the packet has been processed inline. For inline protocol
> > > +	 * processed packets, the metadata in the mbuf can be used to identify
> > > +	 * the security processing done on the packet. The metadata will be
> > > +	 * used to retrieve the application registered userdata associated
> > > +	 * with the security session.
> > > +	 */
> > > +
> > > +	if (pkt->ol_flags & PKT_RX_SEC_OFFLOAD) {
> > > +		struct ipsec_sa *sa;
> > > +		struct ipsec_mbuf_metadata *priv;
> > > +		struct rte_security_ctx *ctx = (struct rte_security_ctx *)
> > > +						rte_eth_dev_get_sec_ctx(
> > > +						pkt->port);
> > > +
> > > +		/* Retrieve the userdata registered. Here, the userdata
> > > +		 * registered is the SA pointer.
> > > +		 */
> > > +
> > > +		sa = (struct ipsec_sa *)
> > > +				rte_security_get_userdata(ctx, pkt->udata64);
> > > +
> > > +		if (sa == NULL) {
> > > +			/* userdata could not be retrieved */
> > > +			return;
> > > +		}
> > > +
> > > +		/* Save SA as priv member in mbuf. This will be used in the
> > > +		 * IPsec selector(SP-SA) check.
> > > +		 */
> > > +
> > > +		priv = get_priv(pkt);
> > > +		priv->sa = sa;
> > > +	}
> > You must verify the function exists on all drivers, those who don't
> > support such userdata to be inserted won't implement it.
> That check is there in library. It will return NULL and then the function
> would exit
> > 
> > What happens on security session where the application don't set such
> > information?  How the application knows the pointer is set correctly?
> Application is the one who sets and gets the pointer. If application doesn't
> set it correctly, application will not able to use it. If application
> doesn't set this, for inline protocol, the application won't have any
> information which it can use to identify the security processing done.
> > 
> > >   }
> > >   static inline void
> > > @@ -401,11 +435,17 @@ inbound_sp_sa(struct sp_ctx *sp, struct sa_ctx *sa, struct traffic_type *ip,
> > >   			ip->pkts[j++] = m;
> > >   			continue;
> > >   		}
> > > -		if (res & DISCARD || i < lim) {
> > > +		if (res & DISCARD) {
> > >   			rte_pktmbuf_free(m);
> > >   			continue;
> > >   		}
> > > +
> > >   		/* Only check SPI match for processed IPSec packets */
> > > +		if (i < lim && ((m->ol_flags & PKT_RX_SEC_OFFLOAD) == 0)) {
> > > +			rte_pktmbuf_free(m);
> > > +			continue;
> > > +		}
> > > +
> > >   		sa_idx = ip->res[i] & PROTECT_MASK;
> > >   		if (sa_idx == 0 || !inbound_sa_check(sa, m, sa_idx)) {
> > >   			rte_pktmbuf_free(m);
> > > diff --git a/examples/ipsec-secgw/ipsec.c b/examples/ipsec-secgw/ipsec.c
> > > index 70ed227..bd68ec6 100644
> > > --- a/examples/ipsec-secgw/ipsec.c
> > > +++ b/examples/ipsec-secgw/ipsec.c
> > > @@ -46,6 +46,27 @@
> > >   #include "ipsec.h"
> > >   #include "esp.h"
> > > +static inline void
> > > +set_ipsec_conf(struct ipsec_sa *sa, struct rte_security_ipsec_xform *ipsec)
> > > +{
> > > +	if (ipsec->mode == RTE_SECURITY_IPSEC_SA_MODE_TUNNEL) {
> > > +		struct rte_security_ipsec_tunnel_param *tunnel =
> > > +				&ipsec->tunnel;
> > > +		if (sa->flags == IP4_TUNNEL) {
> > > +			tunnel->type =
> > > +				RTE_SECURITY_IPSEC_TUNNEL_IPV4;
> > > +			tunnel->ipv4.ttl = IPDEFTTL;
> > > +
> > > +			memcpy((uint8_t *)&tunnel->ipv4.src_ip,
> > > +				(uint8_t *)&sa->src.ip.ip4, 4);
> > > +
> > > +			memcpy((uint8_t *)&tunnel->ipv4.dst_ip,
> > > +				(uint8_t *)&sa->dst.ip.ip4, 4);
> > > +		}
> > > +		/* TODO support for Transport and IPV6 tunnel */
> > > +	}
> > > +}
> > > +
> > >   static inline int
> > >   create_session(struct ipsec_ctx *ipsec_ctx, struct ipsec_sa *sa)
> > >   {
> > > @@ -95,7 +116,8 @@ create_session(struct ipsec_ctx *ipsec_ctx, struct ipsec_sa *sa)
> > >   					RTE_SECURITY_IPSEC_SA_MODE_TUNNEL :
> > >   					RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT,
> > >   			} },
> > > -			.crypto_xform = sa->xforms
> > > +			.crypto_xform = sa->xforms,
> > > +			.userdata = NULL,
> > >   		};
> > > @@ -104,23 +126,8 @@ create_session(struct ipsec_ctx *ipsec_ctx, struct ipsec_sa *sa)
> > >   							rte_cryptodev_get_sec_ctx(
> > >   							ipsec_ctx->tbl[cdev_id_qp].id);
> > > -			if (sess_conf.ipsec.mode ==
> > > -					RTE_SECURITY_IPSEC_SA_MODE_TUNNEL) {
> > > -				struct rte_security_ipsec_tunnel_param *tunnel =
> > > -						&sess_conf.ipsec.tunnel;
> > > -				if (sa->flags == IP4_TUNNEL) {
> > > -					tunnel->type =
> > > -						RTE_SECURITY_IPSEC_TUNNEL_IPV4;
> > > -					tunnel->ipv4.ttl = IPDEFTTL;
> > > -
> > > -					memcpy((uint8_t *)&tunnel->ipv4.src_ip,
> > > -						(uint8_t *)&sa->src.ip.ip4, 4);
> > > -
> > > -					memcpy((uint8_t *)&tunnel->ipv4.dst_ip,
> > > -						(uint8_t *)&sa->dst.ip.ip4, 4);
> > > -				}
> > > -				/* TODO support for Transport and IPV6 tunnel */
> > > -			}
> > > +			/* Set IPsec parameters in conf */
> > > +			set_ipsec_conf(sa, &(sess_conf.ipsec));
> > >   			sa->sec_session = rte_security_session_create(ctx,
> > >   					&sess_conf, ipsec_ctx->session_pool);
> > > @@ -206,6 +213,70 @@ create_session(struct ipsec_ctx *ipsec_ctx, struct ipsec_sa *sa)
> > >   					err.message);
> > >   				return -1;
> > >   			}
> > > +		} else if (sa->type ==
> > > +				RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL) {
> > > +			struct rte_security_ctx *ctx =
> > > +					(struct rte_security_ctx *)
> > > +					rte_eth_dev_get_sec_ctx(sa->portid);
> > > +			const struct rte_security_capability *sec_cap;
> > > +
> > > +			if (ctx == NULL) {
> > > +				RTE_LOG(ERR, IPSEC,
> > > +				"Ethernet device doesn't have security features registered\n");
> > > +				return -1;
> > > +			}
> > > +
> > > +			/* Set IPsec parameters in conf */
> > > +			set_ipsec_conf(sa, &(sess_conf.ipsec));
> > > +
> > > +			/* Save SA as userdata for the security session. When
> > > +			 * the packet is received, this userdata will be
> > > +			 * retrieved using the metadata from the packet.
> > > +			 *
> > > +			 * This is required only for inbound SAs.
> > > +			 */
> > Again not true for all inline devices.
> Should be valid for all inline protocol devices. May be addition of
> capability would look better?
> > 
> > > +
> > > +			if (sa->direction == RTE_SECURITY_IPSEC_SA_DIR_INGRESS)
> > > +				sess_conf.userdata = (void *) sa;
> > > +
> > > +			sa->sec_session = rte_security_session_create(ctx,
> > > +					&sess_conf, ipsec_ctx->session_pool);
> > > +			if (sa->sec_session == NULL) {
> > > +				RTE_LOG(ERR, IPSEC,
> > > +				"SEC Session init failed: err: %d\n", ret);
> > > +				return -1;
> > > +			}
> > > +
> > > +			sec_cap = rte_security_capabilities_get(ctx);
> > > +
> > > +			if (sec_cap == NULL) {
> > > +				RTE_LOG(ERR, IPSEC,
> > > +				"No capabilities registered\n");
> > > +				return -1;
> > > +			}
> > > +
> > > +			/* iterate until ESP tunnel*/
> > > +			while (sec_cap->action !=
> > > +					RTE_SECURITY_ACTION_TYPE_NONE) {
> > > +
> > > +				if (sec_cap->action == sa->type &&
> > > +				    sec_cap->protocol ==
> > > +					RTE_SECURITY_PROTOCOL_IPSEC &&
> > > +				    sec_cap->ipsec.mode ==
> > > +					RTE_SECURITY_IPSEC_SA_MODE_TUNNEL &&
> > > +				    sec_cap->ipsec.direction == sa->direction)
> > > +					break;
> > > +				sec_cap++;
> > > +			}
> > > +
> > > +			if (sec_cap->action == RTE_SECURITY_ACTION_TYPE_NONE) {
> > > +				RTE_LOG(ERR, IPSEC,
> > > +				"No suitable security capability found\n");
> > > +				return -1;
> > > +			}
> > > +
> > > +			sa->ol_flags = sec_cap->ol_flags;
> > > +			sa->security_ctx = ctx;
> > >   		}
> > >   	} else {
> > >   		sa->crypto_session = rte_cryptodev_sym_session_create(
> > > @@ -323,7 +394,19 @@ ipsec_enqueue(ipsec_xform_fn xform_func, struct ipsec_ctx *ipsec_ctx,
> > >   			}
> > >   			break;
> > >   		case RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL:
> > > -			break;
> > > +			if ((unlikely(sa->sec_session == NULL)) &&
> > > +					create_session(ipsec_ctx, sa)) {
> > > +				rte_pktmbuf_free(pkts[i]);
> > > +				continue;
> > > +			}
> > > +
> > > +			cqp = &ipsec_ctx->tbl[sa->cdev_id_qp];
> > > +			cqp->ol_pkts[cqp->ol_pkts_cnt++] = pkts[i];
> > > +			if (sa->ol_flags & RTE_SECURITY_TX_OLOAD_NEED_MDATA)
> > > +				rte_security_set_pkt_metadata(
> > > +						sa->security_ctx,
> > > +						sa->sec_session, pkts[i], NULL);
> > > +			continue;
> > >   		case RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO:
> > >   			priv->cop.type = RTE_CRYPTO_OP_TYPE_SYMMETRIC;
> > >   			priv->cop.status = RTE_CRYPTO_OP_STATUS_NOT_PROCESSED;
> > > -- 
> > > 2.7.4
> > > 
> > Thanks,
> > 
> Thanks,
> Anoob
  

Patch

diff --git a/examples/ipsec-secgw/esp.c b/examples/ipsec-secgw/esp.c
index c3efe52..561f873 100644
--- a/examples/ipsec-secgw/esp.c
+++ b/examples/ipsec-secgw/esp.c
@@ -178,7 +178,8 @@  esp_inbound_post(struct rte_mbuf *m, struct ipsec_sa *sa,
 	RTE_ASSERT(sa != NULL);
 	RTE_ASSERT(cop != NULL);
 
-	if (sa->type == RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO) {
+	if ((sa->type == RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL) ||
+			(sa->type == RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO)) {
 		if (m->ol_flags & PKT_RX_SEC_OFFLOAD) {
 			if (m->ol_flags & PKT_RX_SEC_OFFLOAD_FAILED)
 				cop->status = RTE_CRYPTO_OP_STATUS_ERROR;
@@ -474,7 +475,8 @@  esp_outbound_post(struct rte_mbuf *m,
 	RTE_ASSERT(m != NULL);
 	RTE_ASSERT(sa != NULL);
 
-	if (sa->type == RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO) {
+	if ((sa->type == RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL) ||
+			(sa->type == RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO)) {
 		m->ol_flags |= PKT_TX_SEC_OFFLOAD;
 	} else {
 		RTE_ASSERT(cop != NULL);
diff --git a/examples/ipsec-secgw/ipsec-secgw.c b/examples/ipsec-secgw/ipsec-secgw.c
index c98454a..8254056 100644
--- a/examples/ipsec-secgw/ipsec-secgw.c
+++ b/examples/ipsec-secgw/ipsec-secgw.c
@@ -265,6 +265,40 @@  prepare_one_packet(struct rte_mbuf *pkt, struct ipsec_traffic *t)
 		RTE_LOG(ERR, IPSEC, "Unsupported packet type\n");
 		rte_pktmbuf_free(pkt);
 	}
+
+	/* Check if the packet has been processed inline. For inline protocol
+	 * processed packets, the metadata in the mbuf can be used to identify
+	 * the security processing done on the packet. The metadata will be
+	 * used to retrieve the application registered userdata associated
+	 * with the security session.
+	 */
+
+	if (pkt->ol_flags & PKT_RX_SEC_OFFLOAD) {
+		struct ipsec_sa *sa;
+		struct ipsec_mbuf_metadata *priv;
+		struct rte_security_ctx *ctx = (struct rte_security_ctx *)
+						rte_eth_dev_get_sec_ctx(
+						pkt->port);
+
+		/* Retrieve the userdata registered. Here, the userdata
+		 * registered is the SA pointer.
+		 */
+
+		sa = (struct ipsec_sa *)
+				rte_security_get_userdata(ctx, pkt->udata64);
+
+		if (sa == NULL) {
+			/* userdata could not be retrieved */
+			return;
+		}
+
+		/* Save SA as priv member in mbuf. This will be used in the
+		 * IPsec selector(SP-SA) check.
+		 */
+
+		priv = get_priv(pkt);
+		priv->sa = sa;
+	}
 }
 
 static inline void
@@ -401,11 +435,17 @@  inbound_sp_sa(struct sp_ctx *sp, struct sa_ctx *sa, struct traffic_type *ip,
 			ip->pkts[j++] = m;
 			continue;
 		}
-		if (res & DISCARD || i < lim) {
+		if (res & DISCARD) {
 			rte_pktmbuf_free(m);
 			continue;
 		}
+
 		/* Only check SPI match for processed IPSec packets */
+		if (i < lim && ((m->ol_flags & PKT_RX_SEC_OFFLOAD) == 0)) {
+			rte_pktmbuf_free(m);
+			continue;
+		}
+
 		sa_idx = ip->res[i] & PROTECT_MASK;
 		if (sa_idx == 0 || !inbound_sa_check(sa, m, sa_idx)) {
 			rte_pktmbuf_free(m);
diff --git a/examples/ipsec-secgw/ipsec.c b/examples/ipsec-secgw/ipsec.c
index 70ed227..bd68ec6 100644
--- a/examples/ipsec-secgw/ipsec.c
+++ b/examples/ipsec-secgw/ipsec.c
@@ -46,6 +46,27 @@ 
 #include "ipsec.h"
 #include "esp.h"
 
+static inline void
+set_ipsec_conf(struct ipsec_sa *sa, struct rte_security_ipsec_xform *ipsec)
+{
+	if (ipsec->mode == RTE_SECURITY_IPSEC_SA_MODE_TUNNEL) {
+		struct rte_security_ipsec_tunnel_param *tunnel =
+				&ipsec->tunnel;
+		if (sa->flags == IP4_TUNNEL) {
+			tunnel->type =
+				RTE_SECURITY_IPSEC_TUNNEL_IPV4;
+			tunnel->ipv4.ttl = IPDEFTTL;
+
+			memcpy((uint8_t *)&tunnel->ipv4.src_ip,
+				(uint8_t *)&sa->src.ip.ip4, 4);
+
+			memcpy((uint8_t *)&tunnel->ipv4.dst_ip,
+				(uint8_t *)&sa->dst.ip.ip4, 4);
+		}
+		/* TODO support for Transport and IPV6 tunnel */
+	}
+}
+
 static inline int
 create_session(struct ipsec_ctx *ipsec_ctx, struct ipsec_sa *sa)
 {
@@ -95,7 +116,8 @@  create_session(struct ipsec_ctx *ipsec_ctx, struct ipsec_sa *sa)
 					RTE_SECURITY_IPSEC_SA_MODE_TUNNEL :
 					RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT,
 			} },
-			.crypto_xform = sa->xforms
+			.crypto_xform = sa->xforms,
+			.userdata = NULL,
 
 		};
 
@@ -104,23 +126,8 @@  create_session(struct ipsec_ctx *ipsec_ctx, struct ipsec_sa *sa)
 							rte_cryptodev_get_sec_ctx(
 							ipsec_ctx->tbl[cdev_id_qp].id);
 
-			if (sess_conf.ipsec.mode ==
-					RTE_SECURITY_IPSEC_SA_MODE_TUNNEL) {
-				struct rte_security_ipsec_tunnel_param *tunnel =
-						&sess_conf.ipsec.tunnel;
-				if (sa->flags == IP4_TUNNEL) {
-					tunnel->type =
-						RTE_SECURITY_IPSEC_TUNNEL_IPV4;
-					tunnel->ipv4.ttl = IPDEFTTL;
-
-					memcpy((uint8_t *)&tunnel->ipv4.src_ip,
-						(uint8_t *)&sa->src.ip.ip4, 4);
-
-					memcpy((uint8_t *)&tunnel->ipv4.dst_ip,
-						(uint8_t *)&sa->dst.ip.ip4, 4);
-				}
-				/* TODO support for Transport and IPV6 tunnel */
-			}
+			/* Set IPsec parameters in conf */
+			set_ipsec_conf(sa, &(sess_conf.ipsec));
 
 			sa->sec_session = rte_security_session_create(ctx,
 					&sess_conf, ipsec_ctx->session_pool);
@@ -206,6 +213,70 @@  create_session(struct ipsec_ctx *ipsec_ctx, struct ipsec_sa *sa)
 					err.message);
 				return -1;
 			}
+		} else if (sa->type ==
+				RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL) {
+			struct rte_security_ctx *ctx =
+					(struct rte_security_ctx *)
+					rte_eth_dev_get_sec_ctx(sa->portid);
+			const struct rte_security_capability *sec_cap;
+
+			if (ctx == NULL) {
+				RTE_LOG(ERR, IPSEC,
+				"Ethernet device doesn't have security features registered\n");
+				return -1;
+			}
+
+			/* Set IPsec parameters in conf */
+			set_ipsec_conf(sa, &(sess_conf.ipsec));
+
+			/* Save SA as userdata for the security session. When
+			 * the packet is received, this userdata will be
+			 * retrieved using the metadata from the packet.
+			 *
+			 * This is required only for inbound SAs.
+			 */
+
+			if (sa->direction == RTE_SECURITY_IPSEC_SA_DIR_INGRESS)
+				sess_conf.userdata = (void *) sa;
+
+			sa->sec_session = rte_security_session_create(ctx,
+					&sess_conf, ipsec_ctx->session_pool);
+			if (sa->sec_session == NULL) {
+				RTE_LOG(ERR, IPSEC,
+				"SEC Session init failed: err: %d\n", ret);
+				return -1;
+			}
+
+			sec_cap = rte_security_capabilities_get(ctx);
+
+			if (sec_cap == NULL) {
+				RTE_LOG(ERR, IPSEC,
+				"No capabilities registered\n");
+				return -1;
+			}
+
+			/* iterate until ESP tunnel*/
+			while (sec_cap->action !=
+					RTE_SECURITY_ACTION_TYPE_NONE) {
+
+				if (sec_cap->action == sa->type &&
+				    sec_cap->protocol ==
+					RTE_SECURITY_PROTOCOL_IPSEC &&
+				    sec_cap->ipsec.mode ==
+					RTE_SECURITY_IPSEC_SA_MODE_TUNNEL &&
+				    sec_cap->ipsec.direction == sa->direction)
+					break;
+				sec_cap++;
+			}
+
+			if (sec_cap->action == RTE_SECURITY_ACTION_TYPE_NONE) {
+				RTE_LOG(ERR, IPSEC,
+				"No suitable security capability found\n");
+				return -1;
+			}
+
+			sa->ol_flags = sec_cap->ol_flags;
+			sa->security_ctx = ctx;
 		}
 	} else {
 		sa->crypto_session = rte_cryptodev_sym_session_create(
@@ -323,7 +394,19 @@  ipsec_enqueue(ipsec_xform_fn xform_func, struct ipsec_ctx *ipsec_ctx,
 			}
 			break;
 		case RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL:
-			break;
+			if ((unlikely(sa->sec_session == NULL)) &&
+					create_session(ipsec_ctx, sa)) {
+				rte_pktmbuf_free(pkts[i]);
+				continue;
+			}
+
+			cqp = &ipsec_ctx->tbl[sa->cdev_id_qp];
+			cqp->ol_pkts[cqp->ol_pkts_cnt++] = pkts[i];
+			if (sa->ol_flags & RTE_SECURITY_TX_OLOAD_NEED_MDATA)
+				rte_security_set_pkt_metadata(
+						sa->security_ctx,
+						sa->sec_session, pkts[i], NULL);
+			continue;
 		case RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO:
 			priv->cop.type = RTE_CRYPTO_OP_TYPE_SYMMETRIC;
 			priv->cop.status = RTE_CRYPTO_OP_STATUS_NOT_PROCESSED;