[dpdk-dev] [PATCH v4 12/12] examples/ipsec-secgw: add support for security offload

Aviad Yehezkel aviadye at dev.mellanox.co.il
Sun Oct 15 14:51:38 CEST 2017



On 10/15/2017 1:17 AM, Akhil Goyal wrote:
> Ipsec-secgw application is modified so that it can support
> following type of actions for crypto operations
> 1. full protocol offload using crypto devices.
> 2. inline ipsec using ethernet devices to perform crypto operations
> 3. full protocol offload using ethernet devices.
> 4. non protocol offload
>
> Signed-off-by: Akhil Goyal <akhil.goyal at nxp.com>
> Signed-off-by: Radu Nicolau <radu.nicolau at intel.com>
> Signed-off-by: Boris Pismenny <borisp at mellanox.com>
> Signed-off-by: Declan Doherty <declan.doherty at intel.com>
> Signed-off-by: Aviad Yehezkel <aviadye at mellanox.com>
> ---
>   doc/guides/sample_app_ug/ipsec_secgw.rst |  52 +++++-
>   examples/ipsec-secgw/esp.c               | 120 ++++++++----
>   examples/ipsec-secgw/esp.h               |  10 -
>   examples/ipsec-secgw/ipsec-secgw.c       |   5 +
>   examples/ipsec-secgw/ipsec.c             | 308 ++++++++++++++++++++++++++-----
>   examples/ipsec-secgw/ipsec.h             |  32 +++-
>   examples/ipsec-secgw/sa.c                | 151 +++++++++++----
>   7 files changed, 545 insertions(+), 133 deletions(-)
>
> diff --git a/doc/guides/sample_app_ug/ipsec_secgw.rst b/doc/guides/sample_app_ug/ipsec_secgw.rst
> index b675cba..892977e 100644
> --- a/doc/guides/sample_app_ug/ipsec_secgw.rst
> +++ b/doc/guides/sample_app_ug/ipsec_secgw.rst
> @@ -52,13 +52,22 @@ The application classifies the ports as *Protected* and *Unprotected*.
>   Thus, traffic received on an Unprotected or Protected port is consider
>   Inbound or Outbound respectively.
>   
> +The application also supports complete IPSec protocol offload to hardware
> +(Look aside crypto accelarator or using ethernet device). It also support
> +inline ipsec processing by the supported ethernet device during transmission.
> +These modes can be selected during the SA creation configuration.
> +
> +In case of complete protocol offload, the processing of headers(ESP and outer
> +IP header) is done by the hardware and the application does not need to
> +add/remove them during outbound/inbound processing.
> +
>   The Path for IPsec Inbound traffic is:
>   
>   *  Read packets from the port.
>   *  Classify packets between IPv4 and ESP.
>   *  Perform Inbound SA lookup for ESP packets based on their SPI.
> -*  Perform Verification/Decryption.
> -*  Remove ESP and outer IP header
> +*  Perform Verification/Decryption (Not needed in case of inline ipsec).
> +*  Remove ESP and outer IP header (Not needed in case of protocol offload).
>   *  Inbound SP check using ACL of decrypted packets and any other IPv4 packets.
>   *  Routing.
>   *  Write packet to port.
> @@ -68,8 +77,8 @@ The Path for the IPsec Outbound traffic is:
>   *  Read packets from the port.
>   *  Perform Outbound SP check using ACL of all IPv4 traffic.
>   *  Perform Outbound SA lookup for packets that need IPsec protection.
> -*  Add ESP and outer IP header.
> -*  Perform Encryption/Digest.
> +*  Add ESP and outer IP header (Not needed in case protocol offload).
> +*  Perform Encryption/Digest (Not needed in case of inline ipsec).
>   *  Routing.
>   *  Write packet to port.
>   
> @@ -385,7 +394,7 @@ The SA rule syntax is shown as follows:
>   .. code-block:: console
>   
>       sa <dir> <spi> <cipher_algo> <cipher_key> <auth_algo> <auth_key>
> -    <mode> <src_ip> <dst_ip>
> +    <mode> <src_ip> <dst_ip> <action_type> <port_id>
>   
>   where each options means:
>   
> @@ -526,6 +535,34 @@ where each options means:
>      * *dst X.X.X.X* for IPv4
>      * *dst XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX* for IPv6
>   
> +``<type>``
> +
> + * Action type to specify the security action. This option specify
> +   the SA to be performed with look aside protocol offload to HW
> +   accelerator or protocol offload on ethernet device or inline
> +   crypto processing on the ethernet device during transmission.
> +
> + * Optional: Yes, default type *no-offload*
> +
> + * Available options:
> +
> +   * *lookaside-protocol-offload*: look aside protocol offload to HW accelerator
> +   * *inline-protocol-offload*: inline protocol offload on ethernet device
> +   * *inline-crypto-offload*: inline crypto processing on ethernet device
> +   * *no-offload*: no offloading to hardware
> +
> + ``<port_id>``
> +
> + * Port/device ID of the ethernet/crypto accelerator for which the SA is
> +   configured. This option is used when *type* is NOT *no-offload*
> +
> + * Optional: No, if *type* is not *no-offload*
> +
> + * Syntax:
> +
> +   * *port_id X* X is a valid device number in decimal
> +
> +
>   Example SA rules:
>   
>   .. code-block:: console
> @@ -545,6 +582,11 @@ Example SA rules:
>       aead_key de:ad:be:ef:de:ad:be:ef:de:ad:be:ef:de:ad:be:ef:de:ad:be:ef \
>       mode ipv4-tunnel src 172.16.2.5 dst 172.16.1.5
>   
> +    sa out 5 cipher_algo aes-128-cbc cipher_key 0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0 \
> +    auth_algo sha1-hmac auth_key 0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0 \
> +    mode ipv4-tunnel src 172.16.1.5 dst 172.16.2.5 \
> +    type lookaside-protocol-offload port_id 4
> +
>   Routing rule syntax
>   ^^^^^^^^^^^^^^^^^^^
>   
> diff --git a/examples/ipsec-secgw/esp.c b/examples/ipsec-secgw/esp.c
> index 12c6f8c..781b162 100644
> --- a/examples/ipsec-secgw/esp.c
> +++ b/examples/ipsec-secgw/esp.c
> @@ -58,8 +58,11 @@ esp_inbound(struct rte_mbuf *m, struct ipsec_sa *sa,
>   	struct rte_crypto_sym_op *sym_cop;
>   	int32_t payload_len, ip_hdr_len;
>   
> -	RTE_ASSERT(m != NULL);
>   	RTE_ASSERT(sa != NULL);
> +	if (sa->type == RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO)
> +		return 0;
> +
> +	RTE_ASSERT(m != NULL);
>   	RTE_ASSERT(cop != NULL);
>   
>   	ip4 = rte_pktmbuf_mtod(m, struct ip *);
> @@ -175,29 +178,44 @@ 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 (m->ol_flags & PKT_RX_SEC_OFFLOAD) {
> +			if (m->ol_flags & PKT_RX_SEC_OFFLOAD_FAILED)
> +				cop->status = RTE_CRYPTO_OP_STATUS_ERROR;
> +			else
> +				cop->status = RTE_CRYPTO_OP_STATUS_SUCCESS;
> +		} else
> +			cop->status = RTE_CRYPTO_OP_STATUS_NOT_PROCESSED;
> +	}
> +
>   	if (cop->status != RTE_CRYPTO_OP_STATUS_SUCCESS) {
>   		RTE_LOG(ERR, IPSEC_ESP, "failed crypto op\n");
>   		return -1;
>   	}
>   
> -	nexthdr = rte_pktmbuf_mtod_offset(m, uint8_t*,
> -			rte_pktmbuf_pkt_len(m) - sa->digest_len - 1);
> -	pad_len = nexthdr - 1;
> +	if (sa->type == RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO &&
> +	    sa->ol_flags & RTE_SECURITY_RX_HW_TRAILER_OFFLOAD) {
> +		nexthdr = &m->inner_esp_next_proto;
> +	} else {
> +		nexthdr = rte_pktmbuf_mtod_offset(m, uint8_t*,
> +				rte_pktmbuf_pkt_len(m) - sa->digest_len - 1);
> +		pad_len = nexthdr - 1;
> +
> +		padding = pad_len - *pad_len;
> +		for (i = 0; i < *pad_len; i++) {
> +			if (padding[i] != i + 1) {
> +				RTE_LOG(ERR, IPSEC_ESP, "invalid padding\n");
> +				return -EINVAL;
> +			}
> +		}
>   
> -	padding = pad_len - *pad_len;
> -	for (i = 0; i < *pad_len; i++) {
> -		if (padding[i] != i + 1) {
> -			RTE_LOG(ERR, IPSEC_ESP, "invalid padding\n");
> +		if (rte_pktmbuf_trim(m, *pad_len + 2 + sa->digest_len)) {
> +			RTE_LOG(ERR, IPSEC_ESP,
> +					"failed to remove pad_len + digest\n");
>   			return -EINVAL;
>   		}
>   	}
>   
> -	if (rte_pktmbuf_trim(m, *pad_len + 2 + sa->digest_len)) {
> -		RTE_LOG(ERR, IPSEC_ESP,
> -				"failed to remove pad_len + digest\n");
> -		return -EINVAL;
> -	}
> -
>   	if (unlikely(sa->flags == TRANSPORT)) {
>   		ip = rte_pktmbuf_mtod(m, struct ip *);
>   		ip4 = (struct ip *)rte_pktmbuf_adj(m,
> @@ -226,7 +244,7 @@ esp_outbound(struct rte_mbuf *m, struct ipsec_sa *sa,
>   	struct ip *ip4;
>   	struct ip6_hdr *ip6;
>   	struct esp_hdr *esp = NULL;
> -	uint8_t *padding, *new_ip, nlp;
> +	uint8_t *padding = NULL, *new_ip, nlp;
>   	struct rte_crypto_sym_op *sym_cop;
>   	int32_t i;
>   	uint16_t pad_payload_len, pad_len = 0;
> @@ -236,7 +254,6 @@ esp_outbound(struct rte_mbuf *m, struct ipsec_sa *sa,
>   	RTE_ASSERT(sa != NULL);
>   	RTE_ASSERT(sa->flags == IP4_TUNNEL || sa->flags == IP6_TUNNEL ||
>   		   sa->flags == TRANSPORT);
> -	RTE_ASSERT(cop != NULL);
>   
>   	ip4 = rte_pktmbuf_mtod(m, struct ip *);
>   	if (likely(ip4->ip_v == IPVERSION)) {
> @@ -290,12 +307,19 @@ esp_outbound(struct rte_mbuf *m, struct ipsec_sa *sa,
>   		return -EINVAL;
>   	}
>   
> -	padding = (uint8_t *)rte_pktmbuf_append(m, pad_len + sa->digest_len);
> -	if (unlikely(padding == NULL)) {
> -		RTE_LOG(ERR, IPSEC_ESP, "not enough mbuf trailing space\n");
> -		return -ENOSPC;
> +	/* Add trailer padding if it is not constructed by HW */
> +	if (sa->type != RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO ||
> +	    (sa->type == RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO &&
> +	     !(sa->ol_flags & RTE_SECURITY_TX_HW_TRAILER_OFFLOAD))) {
> +		padding = (uint8_t *)rte_pktmbuf_append(m, pad_len +
> +							sa->digest_len);
> +		if (unlikely(padding == NULL)) {
> +			RTE_LOG(ERR, IPSEC_ESP,
> +					"not enough mbuf trailing space\n");
> +			return -ENOSPC;
> +		}
> +		rte_prefetch0(padding);
>   	}
> -	rte_prefetch0(padding);
>   
>   	switch (sa->flags) {
>   	case IP4_TUNNEL:
> @@ -328,15 +352,46 @@ esp_outbound(struct rte_mbuf *m, struct ipsec_sa *sa,
>   	esp->spi = rte_cpu_to_be_32(sa->spi);
>   	esp->seq = rte_cpu_to_be_32((uint32_t)sa->seq);
>   
> +	/* set iv */
>   	uint64_t *iv = (uint64_t *)(esp + 1);
> +	if (sa->aead_algo == RTE_CRYPTO_AEAD_AES_GCM) {
> +		*iv = rte_cpu_to_be_64(sa->seq);
> +	} else {
> +		switch (sa->cipher_algo) {
> +		case RTE_CRYPTO_CIPHER_NULL:
> +		case RTE_CRYPTO_CIPHER_AES_CBC:
> +			memset(iv, 0, sa->iv_len);
> +			break;
> +		case RTE_CRYPTO_CIPHER_AES_CTR:
> +			*iv = rte_cpu_to_be_64(sa->seq);
> +			break;
> +		default:
> +			RTE_LOG(ERR, IPSEC_ESP,
> +				"unsupported cipher algorithm %u\n",
> +				sa->cipher_algo);
> +			return -EINVAL;
> +		}
> +	}
> +
> +	if (sa->type == RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO) {
> +		if (sa->ol_flags & RTE_SECURITY_TX_HW_TRAILER_OFFLOAD) {
> +			/* Set the inner esp next protocol for HW trailer */
> +			m->inner_esp_next_proto = nlp;
> +			m->packet_type |= RTE_PTYPE_TUNNEL_ESP;
> +		} else {
> +			padding[pad_len - 2] = pad_len - 2;
> +			padding[pad_len - 1] = nlp;
> +		}
> +		goto done;
> +	}
>   
> +	RTE_ASSERT(cop != NULL);
>   	sym_cop = get_sym_cop(cop);
>   	sym_cop->m_src = m;
>   
>   	if (sa->aead_algo == RTE_CRYPTO_AEAD_AES_GCM) {
>   		uint8_t *aad;
>   
> -		*iv = rte_cpu_to_be_64(sa->seq);
>   		sym_cop->aead.data.offset = ip_hdr_len +
>   			sizeof(struct esp_hdr) + sa->iv_len;
>   		sym_cop->aead.data.length = pad_payload_len;
> @@ -365,13 +420,11 @@ esp_outbound(struct rte_mbuf *m, struct ipsec_sa *sa,
>   		switch (sa->cipher_algo) {
>   		case RTE_CRYPTO_CIPHER_NULL:
>   		case RTE_CRYPTO_CIPHER_AES_CBC:
> -			memset(iv, 0, sa->iv_len);
>   			sym_cop->cipher.data.offset = ip_hdr_len +
>   				sizeof(struct esp_hdr);
>   			sym_cop->cipher.data.length = pad_payload_len + sa->iv_len;
>   			break;
>   		case RTE_CRYPTO_CIPHER_AES_CTR:
> -			*iv = rte_cpu_to_be_64(sa->seq);
>   			sym_cop->cipher.data.offset = ip_hdr_len +
>   				sizeof(struct esp_hdr) + sa->iv_len;
>   			sym_cop->cipher.data.length = pad_payload_len;
> @@ -413,21 +466,26 @@ esp_outbound(struct rte_mbuf *m, struct ipsec_sa *sa,
>   				rte_pktmbuf_pkt_len(m) - sa->digest_len);
>   	}
>   
> +done:
>   	return 0;
>   }
>   
>   int
> -esp_outbound_post(struct rte_mbuf *m __rte_unused,
> -		struct ipsec_sa *sa __rte_unused,
> -		struct rte_crypto_op *cop)
> +esp_outbound_post(struct rte_mbuf *m,
> +		  struct ipsec_sa *sa,
> +		  struct rte_crypto_op *cop)
>   {
>   	RTE_ASSERT(m != NULL);
>   	RTE_ASSERT(sa != NULL);
> -	RTE_ASSERT(cop != NULL);
>   
> -	if (cop->status != RTE_CRYPTO_OP_STATUS_SUCCESS) {
> -		RTE_LOG(ERR, IPSEC_ESP, "Failed crypto op\n");
> -		return -1;
> +	if (sa->type == RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO) {
> +		m->ol_flags |= PKT_TX_SEC_OFFLOAD;
> +	} else {
> +		RTE_ASSERT(cop != NULL);
> +		if (cop->status != RTE_CRYPTO_OP_STATUS_SUCCESS) {
> +			RTE_LOG(ERR, IPSEC_ESP, "Failed crypto op\n");
> +			return -1;
> +		}
>   	}
>   
>   	return 0;
> diff --git a/examples/ipsec-secgw/esp.h b/examples/ipsec-secgw/esp.h
> index fa5cc8a..23601e3 100644
> --- a/examples/ipsec-secgw/esp.h
> +++ b/examples/ipsec-secgw/esp.h
> @@ -35,16 +35,6 @@
>   
>   struct mbuf;
>   
> -/* RFC4303 */
> -struct esp_hdr {
> -	uint32_t spi;
> -	uint32_t seq;
> -	/* Payload */
> -	/* Padding */
> -	/* Pad Length */
> -	/* Next Header */
> -	/* Integrity Check Value - ICV */
> -};
>   
>   int
>   esp_inbound(struct rte_mbuf *m, struct ipsec_sa *sa,
> diff --git a/examples/ipsec-secgw/ipsec-secgw.c b/examples/ipsec-secgw/ipsec-secgw.c
> index f931de6..6e18e84 100644
> --- a/examples/ipsec-secgw/ipsec-secgw.c
> +++ b/examples/ipsec-secgw/ipsec-secgw.c
> @@ -1317,6 +1317,11 @@ port_init(uint16_t portid)
>   	printf("Creating queues: nb_rx_queue=%d nb_tx_queue=%u...\n",
>   			nb_rx_queue, nb_tx_queue);
>   
> +	if (dev_info.rx_offload_capa & DEV_RX_OFFLOAD_SECURITY)
> +		port_conf.rxmode.enable_sec = 1;
> +	if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_SECURITY)
> +		port_conf.txmode.enable_sec = 1;
> +
>   	ret = rte_eth_dev_configure(portid, nb_rx_queue, nb_tx_queue,
>   			&port_conf);
>   	if (ret < 0)
> diff --git a/examples/ipsec-secgw/ipsec.c b/examples/ipsec-secgw/ipsec.c
> index daa1d7b..6423e3e 100644
> --- a/examples/ipsec-secgw/ipsec.c
> +++ b/examples/ipsec-secgw/ipsec.c
> @@ -37,7 +37,9 @@
>   #include <rte_branch_prediction.h>
>   #include <rte_log.h>
>   #include <rte_crypto.h>
> +#include <rte_security.h>
>   #include <rte_cryptodev.h>
> +#include <rte_ethdev.h>
>   #include <rte_mbuf.h>
>   #include <rte_hash.h>
>   
> @@ -49,7 +51,7 @@ create_session(struct ipsec_ctx *ipsec_ctx, struct ipsec_sa *sa)
>   {
>   	struct rte_cryptodev_info cdev_info;
>   	unsigned long cdev_id_qp = 0;
> -	int32_t ret;
> +	int32_t ret = 0;
>   	struct cdev_key key = { 0 };
>   
>   	key.lcore_id = (uint8_t)rte_lcore_id();
> @@ -58,16 +60,19 @@ create_session(struct ipsec_ctx *ipsec_ctx, struct ipsec_sa *sa)
>   	key.auth_algo = (uint8_t)sa->auth_algo;
>   	key.aead_algo = (uint8_t)sa->aead_algo;
>   
> -	ret = rte_hash_lookup_data(ipsec_ctx->cdev_map, &key,
> -			(void **)&cdev_id_qp);
> -	if (ret < 0) {
> -		RTE_LOG(ERR, IPSEC, "No cryptodev: core %u, cipher_algo %u, "
> -			"auth_algo %u aead_algo %u\n",
> -			key.lcore_id,
> -			key.cipher_algo,
> -			key.auth_algo,
> -			key.aead_algo);
> -		return -1;
> +	if (sa->type == RTE_SECURITY_ACTION_TYPE_NONE) {
> +		ret = rte_hash_lookup_data(ipsec_ctx->cdev_map, &key,
> +				(void **)&cdev_id_qp);
> +		if (ret < 0) {
> +			RTE_LOG(ERR, IPSEC,
> +				"No cryptodev: core %u, cipher_algo %u, "
> +				"auth_algo %u aead_algo %u\n",
> +				key.lcore_id,
> +				key.cipher_algo,
> +				key.auth_algo,
> +				key.aead_algo);
> +			return -1;
> +		}
>   	}
>   
>   	RTE_LOG_DP(DEBUG, IPSEC, "Create session for SA spi %u on cryptodev "
> @@ -75,23 +80,153 @@ create_session(struct ipsec_ctx *ipsec_ctx, struct ipsec_sa *sa)
>   			ipsec_ctx->tbl[cdev_id_qp].id,
>   			ipsec_ctx->tbl[cdev_id_qp].qp);
>   
> -	sa->crypto_session = rte_cryptodev_sym_session_create(
> -			ipsec_ctx->session_pool);
> -	rte_cryptodev_sym_session_init(ipsec_ctx->tbl[cdev_id_qp].id,
> -			sa->crypto_session, sa->xforms,
> -			ipsec_ctx->session_pool);
> -
> -	rte_cryptodev_info_get(ipsec_ctx->tbl[cdev_id_qp].id, &cdev_info);
> -	if (cdev_info.sym.max_nb_sessions_per_qp > 0) {
> -		ret = rte_cryptodev_queue_pair_attach_sym_session(
> -				ipsec_ctx->tbl[cdev_id_qp].id,
> -				ipsec_ctx->tbl[cdev_id_qp].qp,
> -				sa->crypto_session);
> -		if (ret < 0) {
> -			RTE_LOG(ERR, IPSEC,
> -				"Session cannot be attached to qp %u ",
> -				ipsec_ctx->tbl[cdev_id_qp].qp);
> -			return -1;
> +	if (sa->type != RTE_SECURITY_ACTION_TYPE_NONE) {
> +		struct rte_security_session_conf sess_conf = {
> +			.action_type = sa->type,
> +			.protocol = RTE_SECURITY_PROTOCOL_IPSEC,
> +			.ipsec = {
> +				.spi = sa->spi,
> +				.salt = sa->salt,
> +				.options = { 0 },
> +				.direction = sa->direction,
> +				.proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP,
> +				.mode = (sa->flags == IP4_TUNNEL ||
> +						sa->flags == IP6_TUNNEL) ?
> +					RTE_SECURITY_IPSEC_SA_MODE_TUNNEL :
> +					RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT,
> +			},
> +			.crypto_xform = sa->xforms
> +
> +		};
> +
> +		if (sa->type == RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL) {
> +			struct rte_security_ctx *ctx = (struct rte_security_ctx *)
> +							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 */
> +			}
> +
> +			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;
> +			}
> +		} else if (sa->type == RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO) {
> +			struct rte_flow_error err;
> +			struct rte_security_ctx *ctx = (struct rte_security_ctx *)
> +							rte_eth_dev_get_sec_ctx(
> +							sa->portid);
> +			const struct rte_security_capability *sec_cap;
> +
> +			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);
> +
> +			/* 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;
> +			sa->pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
> +
> +			sa->pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV4;
> +			sa->pattern[1].mask = &rte_flow_item_ipv4_mask;
> +			if (sa->flags & IP6_TUNNEL) {
> +				sa->pattern[1].spec = &sa->ipv6_spec;
> +				memcpy(sa->ipv6_spec.hdr.dst_addr,
> +					sa->dst.ip.ip6.ip6_b, 16);
> +				memcpy(sa->ipv6_spec.hdr.src_addr,
> +				       sa->src.ip.ip6.ip6_b, 16);
> +			} else {
> +				sa->pattern[1].spec = &sa->ipv4_spec;
> +				sa->ipv4_spec.hdr.dst_addr = sa->dst.ip.ip4;
> +				sa->ipv4_spec.hdr.src_addr = sa->src.ip.ip4;
> +			}
> +
> +			sa->pattern[2].type = RTE_FLOW_ITEM_TYPE_ESP;
> +			sa->pattern[2].spec = &sa->esp_spec;
> +			sa->pattern[2].mask = &rte_flow_item_esp_mask;
> +			sa->esp_spec.hdr.spi = sa->spi;
> +
> +			sa->pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
> +
> +			sa->action[0].type = RTE_FLOW_ACTION_TYPE_SECURITY;
> +			sa->action[0].conf = sa->sec_session;
> +
> +			sa->action[1].type = RTE_FLOW_ACTION_TYPE_END;
> +
> +			sa->attr.egress = (sa->direction ==
> +					RTE_SECURITY_IPSEC_SA_DIR_EGRESS);
> +			sa->flow = rte_flow_create(sa->portid,
> +				&sa->attr, sa->pattern, sa->action, &err);
> +			if (sa->flow == NULL) {
> +				RTE_LOG(ERR, IPSEC,
> +					"Failed to create ipsec flow msg: %s\n",
> +					err.message);
> +				return -1;
> +			}
> +		}
> +	} else {
> +		sa->crypto_session = rte_cryptodev_sym_session_create(
> +				ipsec_ctx->session_pool);
> +		rte_cryptodev_sym_session_init(ipsec_ctx->tbl[cdev_id_qp].id,
> +				sa->crypto_session, sa->xforms,
> +				ipsec_ctx->session_pool);
> +
> +		rte_cryptodev_info_get(ipsec_ctx->tbl[cdev_id_qp].id,
> +				&cdev_info);
> +		if (cdev_info.sym.max_nb_sessions_per_qp > 0) {
> +			ret = rte_cryptodev_queue_pair_attach_sym_session(
> +					ipsec_ctx->tbl[cdev_id_qp].id,
> +					ipsec_ctx->tbl[cdev_id_qp].qp,
> +					sa->crypto_session);
> +			if (ret < 0) {
> +				RTE_LOG(ERR, IPSEC,
> +					"Session cannot be attached to qp %u\n",
> +					ipsec_ctx->tbl[cdev_id_qp].qp);
> +				return -1;
> +			}
>   		}
>   	}
>   	sa->cdev_id_qp = cdev_id_qp;
> @@ -129,7 +264,9 @@ ipsec_enqueue(ipsec_xform_fn xform_func, struct ipsec_ctx *ipsec_ctx,
>   {
>   	int32_t ret = 0, i;
>   	struct ipsec_mbuf_metadata *priv;
> +	struct rte_crypto_sym_op *sym_cop;
>   	struct ipsec_sa *sa;
> +	struct cdev_qp *cqp;
>   
>   	for (i = 0; i < nb_pkts; i++) {
>   		if (unlikely(sas[i] == NULL)) {
> @@ -144,23 +281,76 @@ ipsec_enqueue(ipsec_xform_fn xform_func, struct ipsec_ctx *ipsec_ctx,
>   		sa = sas[i];
>   		priv->sa = sa;
>   
> -		priv->cop.type = RTE_CRYPTO_OP_TYPE_SYMMETRIC;
> -		priv->cop.status = RTE_CRYPTO_OP_STATUS_NOT_PROCESSED;
> -
> -		rte_prefetch0(&priv->sym_cop);
> -
> -		if ((unlikely(sa->crypto_session == NULL)) &&
> -				create_session(ipsec_ctx, sa)) {
> -			rte_pktmbuf_free(pkts[i]);
> -			continue;
> -		}
> -
> -		rte_crypto_op_attach_sym_session(&priv->cop,
> -				sa->crypto_session);
> -
> -		ret = xform_func(pkts[i], sa, &priv->cop);
> -		if (unlikely(ret)) {
> -			rte_pktmbuf_free(pkts[i]);
> +		switch (sa->type) {
> +		case RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL:
> +			priv->cop.type = RTE_CRYPTO_OP_TYPE_SYMMETRIC;
> +			priv->cop.status = RTE_CRYPTO_OP_STATUS_NOT_PROCESSED;
> +
> +			rte_prefetch0(&priv->sym_cop);
> +
> +			if ((unlikely(sa->sec_session == NULL)) &&
> +					create_session(ipsec_ctx, sa)) {
> +				rte_pktmbuf_free(pkts[i]);
> +				continue;
> +			}
> +
> +			sym_cop = get_sym_cop(&priv->cop);
> +			sym_cop->m_src = pkts[i];
> +
> +			rte_security_attach_session(&priv->cop,
> +					sa->sec_session);
> +			break;
> +		case RTE_SECURITY_ACTION_TYPE_NONE:
> +
> +			priv->cop.type = RTE_CRYPTO_OP_TYPE_SYMMETRIC;
> +			priv->cop.status = RTE_CRYPTO_OP_STATUS_NOT_PROCESSED;
> +
> +			rte_prefetch0(&priv->sym_cop);
> +
> +			if ((unlikely(sa->crypto_session == NULL)) &&
> +					create_session(ipsec_ctx, sa)) {
> +				rte_pktmbuf_free(pkts[i]);
> +				continue;
> +			}
> +
> +			rte_crypto_op_attach_sym_session(&priv->cop,
> +					sa->crypto_session);
> +
> +			ret = xform_func(pkts[i], sa, &priv->cop);
> +			if (unlikely(ret)) {
> +				rte_pktmbuf_free(pkts[i]);
> +				continue;
> +			}
> +			break;
> +		case RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL:
> +			break;
> +		case RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO:
> +			priv->cop.type = RTE_CRYPTO_OP_TYPE_SYMMETRIC;
> +			priv->cop.status = RTE_CRYPTO_OP_STATUS_NOT_PROCESSED;
> +
> +			rte_prefetch0(&priv->sym_cop);
> +
> +			if ((unlikely(sa->sec_session == NULL)) &&
> +					create_session(ipsec_ctx, sa)) {
> +				rte_pktmbuf_free(pkts[i]);
> +				continue;
> +			}
> +
> +			rte_security_attach_session(&priv->cop,
> +					sa->sec_session);
> +
> +			ret = xform_func(pkts[i], sa, &priv->cop);
> +			if (unlikely(ret)) {
> +				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;
>   		}
>   
> @@ -171,7 +361,7 @@ ipsec_enqueue(ipsec_xform_fn xform_func, struct ipsec_ctx *ipsec_ctx,
>   
>   static inline int
>   ipsec_dequeue(ipsec_xform_fn xform_func, struct ipsec_ctx *ipsec_ctx,
> -		struct rte_mbuf *pkts[], uint16_t max_pkts)
> +	      struct rte_mbuf *pkts[], uint16_t max_pkts)
>   {
>   	int32_t nb_pkts = 0, ret = 0, i, j, nb_cops;
>   	struct ipsec_mbuf_metadata *priv;
> @@ -186,6 +376,19 @@ ipsec_dequeue(ipsec_xform_fn xform_func, struct ipsec_ctx *ipsec_ctx,
>   		if (ipsec_ctx->last_qp == ipsec_ctx->nb_qps)
>   			ipsec_ctx->last_qp %= ipsec_ctx->nb_qps;
>   
> +		while (cqp->ol_pkts_cnt > 0 && nb_pkts < max_pkts) {
> +			pkt = cqp->ol_pkts[--cqp->ol_pkts_cnt];
> +			rte_prefetch0(pkt);
> +			priv = get_priv(pkt);
> +			sa = priv->sa;
> +			ret = xform_func(pkt, sa, &priv->cop);
> +			if (unlikely(ret)) {
> +				rte_pktmbuf_free(pkt);
> +				continue;
> +			}
> +			pkts[nb_pkts++] = pkt;
> +		}
> +
>   		if (cqp->in_flight == 0)
>   			continue;
>   
> @@ -203,11 +406,14 @@ ipsec_dequeue(ipsec_xform_fn xform_func, struct ipsec_ctx *ipsec_ctx,
>   
>   			RTE_ASSERT(sa != NULL);
>   
> -			ret = xform_func(pkt, sa, cops[j]);
> -			if (unlikely(ret))
> -				rte_pktmbuf_free(pkt);
> -			else
> -				pkts[nb_pkts++] = pkt;
> +			if (sa->type == RTE_SECURITY_ACTION_TYPE_NONE) {
> +				ret = xform_func(pkt, sa, cops[j]);
> +				if (unlikely(ret)) {
> +					rte_pktmbuf_free(pkt);
> +					continue;
> +				}
> +			}
> +			pkts[nb_pkts++] = pkt;
>   		}
>   	}
>   
> diff --git a/examples/ipsec-secgw/ipsec.h b/examples/ipsec-secgw/ipsec.h
> index 9e22b1b..613785f 100644
> --- a/examples/ipsec-secgw/ipsec.h
> +++ b/examples/ipsec-secgw/ipsec.h
> @@ -38,6 +38,8 @@
>   
>   #include <rte_byteorder.h>
>   #include <rte_crypto.h>
> +#include <rte_security.h>
> +#include <rte_flow.h>
>   
>   #define RTE_LOGTYPE_IPSEC       RTE_LOGTYPE_USER1
>   #define RTE_LOGTYPE_IPSEC_ESP   RTE_LOGTYPE_USER2
> @@ -99,7 +101,10 @@ struct ipsec_sa {
>   	uint32_t cdev_id_qp;
>   	uint64_t seq;
>   	uint32_t salt;
> -	struct rte_cryptodev_sym_session *crypto_session;
> +	union {
> +		struct rte_cryptodev_sym_session *crypto_session;
> +		struct rte_security_session *sec_session;
> +	};
>   	enum rte_crypto_cipher_algorithm cipher_algo;
>   	enum rte_crypto_auth_algorithm auth_algo;
>   	enum rte_crypto_aead_algorithm aead_algo;
> @@ -117,7 +122,28 @@ struct ipsec_sa {
>   	uint8_t auth_key[MAX_KEY_SIZE];
>   	uint16_t auth_key_len;
>   	uint16_t aad_len;
> -	struct rte_crypto_sym_xform *xforms;
> +	union {
> +		struct rte_crypto_sym_xform *xforms;
> +		struct rte_security_ipsec_xform *sec_xform;
> +	};
> +	enum rte_security_session_action_type type;
> +	enum rte_security_ipsec_sa_direction direction;
> +	uint16_t portid;
> +	struct rte_security_ctx *security_ctx;
> +	uint32_t ol_flags;
> +
> +#define MAX_RTE_FLOW_PATTERN (4)
> +#define MAX_RTE_FLOW_ACTIONS (2)
> +	struct rte_flow_item pattern[MAX_RTE_FLOW_PATTERN];
> +	struct rte_flow_action action[MAX_RTE_FLOW_ACTIONS];
> +	struct rte_flow_attr attr;
> +	union {
> +		struct rte_flow_item_ipv4 ipv4_spec;
> +		struct rte_flow_item_ipv6 ipv6_spec;
> +	};
> +	struct rte_flow_item_esp esp_spec;
> +	struct rte_flow *flow;
> +	struct rte_security_session_conf sess_conf;
>   } __rte_cache_aligned;
>   
>   struct ipsec_mbuf_metadata {
> @@ -133,6 +159,8 @@ struct cdev_qp {
>   	uint16_t in_flight;
>   	uint16_t len;
>   	struct rte_crypto_op *buf[MAX_PKT_BURST] __rte_aligned(sizeof(void *));
> +	struct rte_mbuf *ol_pkts[MAX_PKT_BURST] __rte_aligned(sizeof(void *));
> +	uint16_t ol_pkts_cnt;
>   };
>   
>   struct ipsec_ctx {
> diff --git a/examples/ipsec-secgw/sa.c b/examples/ipsec-secgw/sa.c
> index ef94475..d8ee47b 100644
> --- a/examples/ipsec-secgw/sa.c
> +++ b/examples/ipsec-secgw/sa.c
> @@ -41,16 +41,20 @@
>   
>   #include <rte_memzone.h>
>   #include <rte_crypto.h>
> +#include <rte_security.h>
>   #include <rte_cryptodev.h>
>   #include <rte_byteorder.h>
>   #include <rte_errno.h>
>   #include <rte_ip.h>
>   #include <rte_random.h>
> +#include <rte_ethdev.h>
>   
>   #include "ipsec.h"
>   #include "esp.h"
>   #include "parser.h"
>   
> +#define IPDEFTTL 64
> +
>   struct supported_cipher_algo {
>   	const char *keyword;
>   	enum rte_crypto_cipher_algorithm algo;
> @@ -238,6 +242,8 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
>   	uint32_t src_p = 0;
>   	uint32_t dst_p = 0;
>   	uint32_t mode_p = 0;
> +	uint32_t type_p = 0;
> +	uint32_t portid_p = 0;
>   
>   	if (strcmp(tokens[0], "in") == 0) {
>   		ri = &nb_sa_in;
> @@ -550,6 +556,52 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
>   			continue;
>   		}
>   
> +		if (strcmp(tokens[ti], "type") == 0) {
> +			APP_CHECK_PRESENCE(type_p, tokens[ti], status);
> +			if (status->status < 0)
> +				return;
> +
> +			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
> +			if (status->status < 0)
> +				return;
> +
> +			if (strcmp(tokens[ti], "inline-crypto-offload") == 0)
> +				rule->type =
> +					RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO;
> +			else if (strcmp(tokens[ti],
> +					"inline-protocol-offload") == 0)
> +				rule->type =
> +				RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL;
> +			else if (strcmp(tokens[ti],
> +					"lookaside-protocol-offload") == 0)
> +				rule->type =
> +				RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL;
> +			else if (strcmp(tokens[ti], "no-offload") == 0)
> +				rule->type = RTE_SECURITY_ACTION_TYPE_NONE;
> +			else {
> +				APP_CHECK(0, status, "Invalid input \"%s\"",
> +						tokens[ti]);
> +				return;
> +			}
> +
> +			type_p = 1;
> +			continue;
> +		}
> +
> +		if (strcmp(tokens[ti], "port_id") == 0) {
> +			APP_CHECK_PRESENCE(portid_p, tokens[ti], status);
> +			if (status->status < 0)
> +				return;
> +			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
> +			if (status->status < 0)
> +				return;
> +			rule->portid = atoi(tokens[ti]);
> +			if (status->status < 0)
> +				return;
> +			portid_p = 1;
> +			continue;
> +		}
> +
>   		/* unrecognizeable input */
>   		APP_CHECK(0, status, "unrecognized input \"%s\"",
>   			tokens[ti]);
> @@ -580,6 +632,14 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
>   	if (status->status < 0)
>   		return;
>   
> +	if ((rule->type != RTE_SECURITY_ACTION_TYPE_NONE) && (portid_p == 0))
> +		printf("Missing portid option, falling back to non-offload\n");
> +
> +	if (!type_p || !portid_p) {
> +		rule->type = RTE_SECURITY_ACTION_TYPE_NONE;
> +		rule->portid = -1;
> +	}
> +
>   	*ri = *ri + 1;
>   }
>   
> @@ -647,9 +707,11 @@ print_one_sa_rule(const struct ipsec_sa *sa, int inbound)
>   
>   struct sa_ctx {
>   	struct ipsec_sa sa[IPSEC_SA_MAX_ENTRIES];
> -	struct {
> -		struct rte_crypto_sym_xform a;
> -		struct rte_crypto_sym_xform b;
> +	union {
> +		struct {
> +			struct rte_crypto_sym_xform a;
> +			struct rte_crypto_sym_xform b;
> +		};
>   	} xf[IPSEC_SA_MAX_ENTRIES];
>   };
>   
> @@ -682,6 +744,33 @@ sa_create(const char *name, int32_t socket_id)
>   }
>   
>   static int
> +check_eth_dev_caps(uint16_t portid, uint32_t inbound)
> +{
> +	struct rte_eth_dev_info dev_info;
> +
> +	rte_eth_dev_info_get(portid, &dev_info);
> +
> +	if (inbound) {
> +		if ((dev_info.rx_offload_capa &
> +				DEV_RX_OFFLOAD_SECURITY) == 0) {
> +			RTE_LOG(WARNING, PORT,
> +				"hardware RX IPSec offload is not supported\n");
> +			return -EINVAL;
> +		}
> +
> +	} else { /* outbound */
> +		if ((dev_info.tx_offload_capa &
> +				DEV_TX_OFFLOAD_SECURITY) == 0) {
> +			RTE_LOG(WARNING, PORT,
> +				"hardware TX IPSec offload is not supported\n");
> +			return -EINVAL;
> +		}
> +	}
> +	return 0;
> +}
> +
> +
> +static int
>   sa_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
>   		uint32_t nb_entries, uint32_t inbound)
>   {
> @@ -700,6 +789,16 @@ sa_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
>   		*sa = entries[i];
>   		sa->seq = 0;
>   
> +		if (sa->type == RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL ||
> +			sa->type == RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO) {
> +			if (check_eth_dev_caps(sa->portid, inbound))
> +				return -EINVAL;
> +		}
> +
> +		sa->direction = (inbound == 1) ?
> +				RTE_SECURITY_IPSEC_SA_DIR_INGRESS :
> +				RTE_SECURITY_IPSEC_SA_DIR_EGRESS;
> +
>   		switch (sa->flags) {
>   		case IP4_TUNNEL:
>   			sa->src.ip.ip4 = rte_cpu_to_be_32(sa->src.ip.ip4);
> @@ -709,37 +808,21 @@ sa_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
>   		if (sa->aead_algo == RTE_CRYPTO_AEAD_AES_GCM) {
>   			iv_length = 16;
>   
> -			if (inbound) {
> -				sa_ctx->xf[idx].a.type = RTE_CRYPTO_SYM_XFORM_AEAD;
> -				sa_ctx->xf[idx].a.aead.algo = sa->aead_algo;
> -				sa_ctx->xf[idx].a.aead.key.data = sa->cipher_key;
> -				sa_ctx->xf[idx].a.aead.key.length =
> -					sa->cipher_key_len;
> -				sa_ctx->xf[idx].a.aead.op =
> -					RTE_CRYPTO_AEAD_OP_DECRYPT;
> -				sa_ctx->xf[idx].a.next = NULL;
> -				sa_ctx->xf[idx].a.aead.iv.offset = IV_OFFSET;
> -				sa_ctx->xf[idx].a.aead.iv.length = iv_length;
> -				sa_ctx->xf[idx].a.aead.aad_length =
> -					sa->aad_len;
> -				sa_ctx->xf[idx].a.aead.digest_length =
> -					sa->digest_len;
> -			} else { /* outbound */
> -				sa_ctx->xf[idx].a.type = RTE_CRYPTO_SYM_XFORM_AEAD;
> -				sa_ctx->xf[idx].a.aead.algo = sa->aead_algo;
> -				sa_ctx->xf[idx].a.aead.key.data = sa->cipher_key;
> -				sa_ctx->xf[idx].a.aead.key.length =
> -					sa->cipher_key_len;
> -				sa_ctx->xf[idx].a.aead.op =
> -					RTE_CRYPTO_AEAD_OP_ENCRYPT;
> -				sa_ctx->xf[idx].a.next = NULL;
> -				sa_ctx->xf[idx].a.aead.iv.offset = IV_OFFSET;
> -				sa_ctx->xf[idx].a.aead.iv.length = iv_length;
> -				sa_ctx->xf[idx].a.aead.aad_length =
> -					sa->aad_len;
> -				sa_ctx->xf[idx].a.aead.digest_length =
> -					sa->digest_len;
> -			}
> +			sa_ctx->xf[idx].a.type = RTE_CRYPTO_SYM_XFORM_AEAD;
> +			sa_ctx->xf[idx].a.aead.algo = sa->aead_algo;
> +			sa_ctx->xf[idx].a.aead.key.data = sa->cipher_key;
> +			sa_ctx->xf[idx].a.aead.key.length =
> +				sa->cipher_key_len;
> +			sa_ctx->xf[idx].a.aead.op = (inbound == 1) ?
> +				RTE_CRYPTO_AEAD_OP_DECRYPT :
> +				RTE_CRYPTO_AEAD_OP_ENCRYPT;
> +			sa_ctx->xf[idx].a.next = NULL;
> +			sa_ctx->xf[idx].a.aead.iv.offset = IV_OFFSET;
> +			sa_ctx->xf[idx].a.aead.iv.length = iv_length;
> +			sa_ctx->xf[idx].a.aead.aad_length =
> +				sa->aad_len;
> +			sa_ctx->xf[idx].a.aead.digest_length =
> +				sa->digest_len;
>   
>   			sa->xforms = &sa_ctx->xf[idx].a;
>   

Tested-by: Aviad Yehezkel <aviadye at mellanox.com>



More information about the dev mailing list