Inline processing is limited to a specified subset of traffic. It is often unable to handle more complicated situations, such as fragmented traffic. When using inline processing such traffic is dropped. Introduce fallback session for inline crypto processing allowing handling packets that normally would be dropped. A fallback session is configured by adding 'fallback' keyword with 'lookaside-none' parameter to an SA configuration. Only 'inline-crypto-offload" as a primary session and 'lookaside-none' as a fall-back session combination is supported by this patch. Fallback session feature is not available in the legacy mode. Signed-off-by: Marcin Smoczynski <marcinx.smoczynski@intel.com> Acked-by: Konstantin Ananyev <konstantin.ananyev@intel.com> Acked-by: Akhil Goyal <akhil.goyal@nxp.com> Tested-by: Bernard Iremonger <bernard.iremonger@intel.com>
656 lines
17 KiB
C
656 lines
17 KiB
C
/* SPDX-License-Identifier: BSD-3-Clause
|
|
* Copyright(c) 2016-2017 Intel Corporation
|
|
*/
|
|
#include <sys/types.h>
|
|
#include <netinet/in.h>
|
|
#include <netinet/ip.h>
|
|
|
|
#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>
|
|
|
|
#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 (IS_IP4_TUNNEL(sa->flags)) {
|
|
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);
|
|
} else if (IS_IP6_TUNNEL(sa->flags)) {
|
|
tunnel->type =
|
|
RTE_SECURITY_IPSEC_TUNNEL_IPV6;
|
|
tunnel->ipv6.hlimit = IPDEFTTL;
|
|
tunnel->ipv6.dscp = 0;
|
|
tunnel->ipv6.flabel = 0;
|
|
|
|
memcpy((uint8_t *)&tunnel->ipv6.src_addr,
|
|
(uint8_t *)&sa->src.ip.ip6.ip6_b, 16);
|
|
|
|
memcpy((uint8_t *)&tunnel->ipv6.dst_addr,
|
|
(uint8_t *)&sa->dst.ip.ip6.ip6_b, 16);
|
|
}
|
|
/* TODO support for Transport */
|
|
}
|
|
ipsec->esn_soft_limit = IPSEC_OFFLOAD_ESN_SOFTLIMIT;
|
|
}
|
|
|
|
int
|
|
create_lookaside_session(struct ipsec_ctx *ipsec_ctx, struct ipsec_sa *sa,
|
|
struct rte_ipsec_session *ips)
|
|
{
|
|
struct rte_cryptodev_info cdev_info;
|
|
unsigned long cdev_id_qp = 0;
|
|
int32_t ret = 0;
|
|
struct cdev_key key = { 0 };
|
|
|
|
key.lcore_id = (uint8_t)rte_lcore_id();
|
|
|
|
key.cipher_algo = (uint8_t)sa->cipher_algo;
|
|
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;
|
|
}
|
|
|
|
RTE_LOG_DP(DEBUG, IPSEC, "Create session for SA spi %u on cryptodev "
|
|
"%u qp %u\n", sa->spi,
|
|
ipsec_ctx->tbl[cdev_id_qp].id,
|
|
ipsec_ctx->tbl[cdev_id_qp].qp);
|
|
|
|
if (ips->type != RTE_SECURITY_ACTION_TYPE_NONE) {
|
|
struct rte_security_session_conf sess_conf = {
|
|
.action_type = ips->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 = (IS_TUNNEL(sa->flags)) ?
|
|
RTE_SECURITY_IPSEC_SA_MODE_TUNNEL :
|
|
RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT,
|
|
} },
|
|
.crypto_xform = sa->xforms,
|
|
.userdata = NULL,
|
|
|
|
};
|
|
|
|
if (ips->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);
|
|
|
|
/* Set IPsec parameters in conf */
|
|
set_ipsec_conf(sa, &(sess_conf.ipsec));
|
|
|
|
ips->security.ses = rte_security_session_create(ctx,
|
|
&sess_conf, ipsec_ctx->session_priv_pool);
|
|
if (ips->security.ses == NULL) {
|
|
RTE_LOG(ERR, IPSEC,
|
|
"SEC Session init failed: err: %d\n", ret);
|
|
return -1;
|
|
}
|
|
} else {
|
|
RTE_LOG(ERR, IPSEC, "Inline not supported\n");
|
|
return -1;
|
|
}
|
|
} else {
|
|
ips->crypto.ses = rte_cryptodev_sym_session_create(
|
|
ipsec_ctx->session_pool);
|
|
rte_cryptodev_sym_session_init(ipsec_ctx->tbl[cdev_id_qp].id,
|
|
ips->crypto.ses, sa->xforms,
|
|
ipsec_ctx->session_priv_pool);
|
|
|
|
rte_cryptodev_info_get(ipsec_ctx->tbl[cdev_id_qp].id,
|
|
&cdev_info);
|
|
}
|
|
|
|
sa->cdev_id_qp = cdev_id_qp;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
create_inline_session(struct socket_ctx *skt_ctx, struct ipsec_sa *sa,
|
|
struct rte_ipsec_session *ips)
|
|
{
|
|
int32_t ret = 0;
|
|
struct rte_security_ctx *sec_ctx;
|
|
struct rte_security_session_conf sess_conf = {
|
|
.action_type = ips->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,
|
|
.userdata = NULL,
|
|
};
|
|
|
|
RTE_LOG_DP(DEBUG, IPSEC, "Create session for SA spi %u on port %u\n",
|
|
sa->spi, sa->portid);
|
|
|
|
if (ips->type == RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO) {
|
|
struct rte_flow_error err;
|
|
const struct rte_security_capability *sec_cap;
|
|
int ret = 0;
|
|
|
|
sec_ctx = (struct rte_security_ctx *)
|
|
rte_eth_dev_get_sec_ctx(
|
|
sa->portid);
|
|
if (sec_ctx == NULL) {
|
|
RTE_LOG(ERR, IPSEC,
|
|
" rte_eth_dev_get_sec_ctx failed\n");
|
|
return -1;
|
|
}
|
|
|
|
ips->security.ses = rte_security_session_create(sec_ctx,
|
|
&sess_conf, skt_ctx->session_pool);
|
|
if (ips->security.ses == NULL) {
|
|
RTE_LOG(ERR, IPSEC,
|
|
"SEC Session init failed: err: %d\n", ret);
|
|
return -1;
|
|
}
|
|
|
|
sec_cap = rte_security_capabilities_get(sec_ctx);
|
|
|
|
/* iterate until ESP tunnel*/
|
|
while (sec_cap->action != RTE_SECURITY_ACTION_TYPE_NONE) {
|
|
if (sec_cap->action == ips->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;
|
|
}
|
|
|
|
ips->security.ol_flags = sec_cap->ol_flags;
|
|
ips->security.ctx = sec_ctx;
|
|
sa->pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
|
|
|
|
if (IS_IP6(sa->flags)) {
|
|
sa->pattern[1].mask = &rte_flow_item_ipv6_mask;
|
|
sa->pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV6;
|
|
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 if (IS_IP4(sa->flags)) {
|
|
sa->pattern[1].mask = &rte_flow_item_ipv4_mask;
|
|
sa->pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV4;
|
|
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 = rte_cpu_to_be_32(sa->spi);
|
|
|
|
sa->pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
|
|
|
|
sa->action[0].type = RTE_FLOW_ACTION_TYPE_SECURITY;
|
|
sa->action[0].conf = ips->security.ses;
|
|
|
|
sa->action[1].type = RTE_FLOW_ACTION_TYPE_END;
|
|
|
|
sa->attr.egress = (sa->direction ==
|
|
RTE_SECURITY_IPSEC_SA_DIR_EGRESS);
|
|
sa->attr.ingress = (sa->direction ==
|
|
RTE_SECURITY_IPSEC_SA_DIR_INGRESS);
|
|
if (sa->attr.ingress) {
|
|
uint8_t rss_key[40];
|
|
struct rte_eth_rss_conf rss_conf = {
|
|
.rss_key = rss_key,
|
|
.rss_key_len = 40,
|
|
};
|
|
struct rte_eth_dev_info dev_info;
|
|
uint16_t queue[RTE_MAX_QUEUES_PER_PORT];
|
|
struct rte_flow_action_rss action_rss;
|
|
unsigned int i;
|
|
unsigned int j;
|
|
|
|
ret = rte_eth_dev_info_get(sa->portid, &dev_info);
|
|
if (ret != 0) {
|
|
RTE_LOG(ERR, IPSEC,
|
|
"Error during getting device (port %u) info: %s\n",
|
|
sa->portid, strerror(-ret));
|
|
return ret;
|
|
}
|
|
|
|
sa->action[2].type = RTE_FLOW_ACTION_TYPE_END;
|
|
/* Try RSS. */
|
|
sa->action[1].type = RTE_FLOW_ACTION_TYPE_RSS;
|
|
sa->action[1].conf = &action_rss;
|
|
ret = rte_eth_dev_rss_hash_conf_get(sa->portid,
|
|
&rss_conf);
|
|
if (ret != 0) {
|
|
RTE_LOG(ERR, IPSEC,
|
|
"rte_eth_dev_rss_hash_conf_get:ret=%d\n",
|
|
ret);
|
|
return -1;
|
|
}
|
|
for (i = 0, j = 0; i < dev_info.nb_rx_queues; ++i)
|
|
queue[j++] = i;
|
|
|
|
action_rss = (struct rte_flow_action_rss){
|
|
.types = rss_conf.rss_hf,
|
|
.key_len = rss_conf.rss_key_len,
|
|
.queue_num = j,
|
|
.key = rss_key,
|
|
.queue = queue,
|
|
};
|
|
ret = rte_flow_validate(sa->portid, &sa->attr,
|
|
sa->pattern, sa->action,
|
|
&err);
|
|
if (!ret)
|
|
goto flow_create;
|
|
/* Try Queue. */
|
|
sa->action[1].type = RTE_FLOW_ACTION_TYPE_QUEUE;
|
|
sa->action[1].conf =
|
|
&(struct rte_flow_action_queue){
|
|
.index = 0,
|
|
};
|
|
ret = rte_flow_validate(sa->portid, &sa->attr,
|
|
sa->pattern, sa->action,
|
|
&err);
|
|
/* Try End. */
|
|
sa->action[1].type = RTE_FLOW_ACTION_TYPE_END;
|
|
sa->action[1].conf = NULL;
|
|
ret = rte_flow_validate(sa->portid, &sa->attr,
|
|
sa->pattern, sa->action,
|
|
&err);
|
|
if (ret)
|
|
goto flow_create_failure;
|
|
} else if (sa->attr.egress &&
|
|
(ips->security.ol_flags &
|
|
RTE_SECURITY_TX_HW_TRAILER_OFFLOAD)) {
|
|
sa->action[1].type =
|
|
RTE_FLOW_ACTION_TYPE_PASSTHRU;
|
|
sa->action[2].type =
|
|
RTE_FLOW_ACTION_TYPE_END;
|
|
}
|
|
flow_create:
|
|
sa->flow = rte_flow_create(sa->portid,
|
|
&sa->attr, sa->pattern, sa->action, &err);
|
|
if (sa->flow == NULL) {
|
|
flow_create_failure:
|
|
RTE_LOG(ERR, IPSEC,
|
|
"Failed to create ipsec flow msg: %s\n",
|
|
err.message);
|
|
return -1;
|
|
}
|
|
} else if (ips->type == RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL) {
|
|
const struct rte_security_capability *sec_cap;
|
|
|
|
sec_ctx = (struct rte_security_ctx *)
|
|
rte_eth_dev_get_sec_ctx(sa->portid);
|
|
|
|
if (sec_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.
|
|
*
|
|
* The PMD is expected to set similar metadata for other
|
|
* operations, like rte_eth_event, which are tied to
|
|
* security session. In such cases, the userdata could
|
|
* be obtained to uniquely identify the security
|
|
* parameters denoted.
|
|
*/
|
|
|
|
sess_conf.userdata = (void *) sa;
|
|
|
|
ips->security.ses = rte_security_session_create(sec_ctx,
|
|
&sess_conf, skt_ctx->session_pool);
|
|
if (ips->security.ses == NULL) {
|
|
RTE_LOG(ERR, IPSEC,
|
|
"SEC Session init failed: err: %d\n", ret);
|
|
return -1;
|
|
}
|
|
|
|
sec_cap = rte_security_capabilities_get(sec_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 == ips->type &&
|
|
sec_cap->protocol ==
|
|
RTE_SECURITY_PROTOCOL_IPSEC &&
|
|
sec_cap->ipsec.mode ==
|
|
sess_conf.ipsec.mode &&
|
|
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;
|
|
}
|
|
|
|
ips->security.ol_flags = sec_cap->ol_flags;
|
|
ips->security.ctx = sec_ctx;
|
|
}
|
|
sa->cdev_id_qp = 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* queue crypto-ops into PMD queue.
|
|
*/
|
|
void
|
|
enqueue_cop_burst(struct cdev_qp *cqp)
|
|
{
|
|
uint32_t i, len, ret;
|
|
|
|
len = cqp->len;
|
|
ret = rte_cryptodev_enqueue_burst(cqp->id, cqp->qp, cqp->buf, len);
|
|
if (ret < len) {
|
|
RTE_LOG_DP(DEBUG, IPSEC, "Cryptodev %u queue %u:"
|
|
" enqueued %u crypto ops out of %u\n",
|
|
cqp->id, cqp->qp, ret, len);
|
|
/* drop packets that we fail to enqueue */
|
|
for (i = ret; i < len; i++)
|
|
rte_pktmbuf_free(cqp->buf[i]->sym->m_src);
|
|
}
|
|
cqp->in_flight += ret;
|
|
cqp->len = 0;
|
|
}
|
|
|
|
static inline void
|
|
enqueue_cop(struct cdev_qp *cqp, struct rte_crypto_op *cop)
|
|
{
|
|
cqp->buf[cqp->len++] = cop;
|
|
|
|
if (cqp->len == MAX_PKT_BURST)
|
|
enqueue_cop_burst(cqp);
|
|
}
|
|
|
|
static inline void
|
|
ipsec_enqueue(ipsec_xform_fn xform_func, struct ipsec_ctx *ipsec_ctx,
|
|
struct rte_mbuf *pkts[], void *sas[],
|
|
uint16_t nb_pkts)
|
|
{
|
|
int32_t ret = 0, i;
|
|
struct ipsec_mbuf_metadata *priv;
|
|
struct rte_crypto_sym_op *sym_cop;
|
|
struct ipsec_sa *sa;
|
|
struct rte_ipsec_session *ips;
|
|
|
|
for (i = 0; i < nb_pkts; i++) {
|
|
if (unlikely(sas[i] == NULL)) {
|
|
rte_pktmbuf_free(pkts[i]);
|
|
continue;
|
|
}
|
|
|
|
rte_prefetch0(sas[i]);
|
|
rte_prefetch0(pkts[i]);
|
|
|
|
priv = get_priv(pkts[i]);
|
|
sa = ipsec_mask_saptr(sas[i]);
|
|
priv->sa = sa;
|
|
ips = ipsec_get_primary_session(sa);
|
|
|
|
switch (ips->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(ips->security.ses == NULL)) &&
|
|
create_lookaside_session(ipsec_ctx, sa, ips)) {
|
|
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,
|
|
ips->security.ses);
|
|
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(ips->crypto.ses == NULL)) &&
|
|
create_lookaside_session(ipsec_ctx, sa, ips)) {
|
|
rte_pktmbuf_free(pkts[i]);
|
|
continue;
|
|
}
|
|
|
|
rte_crypto_op_attach_sym_session(&priv->cop,
|
|
ips->crypto.ses);
|
|
|
|
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:
|
|
RTE_ASSERT(ips->security.ses != NULL);
|
|
ipsec_ctx->ol_pkts[ipsec_ctx->ol_pkts_cnt++] = pkts[i];
|
|
if (ips->security.ol_flags &
|
|
RTE_SECURITY_TX_OLOAD_NEED_MDATA)
|
|
rte_security_set_pkt_metadata(
|
|
ips->security.ctx, ips->security.ses,
|
|
pkts[i], NULL);
|
|
continue;
|
|
case RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO:
|
|
RTE_ASSERT(ips->security.ses != NULL);
|
|
priv->cop.type = RTE_CRYPTO_OP_TYPE_SYMMETRIC;
|
|
priv->cop.status = RTE_CRYPTO_OP_STATUS_NOT_PROCESSED;
|
|
|
|
rte_prefetch0(&priv->sym_cop);
|
|
rte_security_attach_session(&priv->cop,
|
|
ips->security.ses);
|
|
|
|
ret = xform_func(pkts[i], sa, &priv->cop);
|
|
if (unlikely(ret)) {
|
|
rte_pktmbuf_free(pkts[i]);
|
|
continue;
|
|
}
|
|
|
|
ipsec_ctx->ol_pkts[ipsec_ctx->ol_pkts_cnt++] = pkts[i];
|
|
if (ips->security.ol_flags &
|
|
RTE_SECURITY_TX_OLOAD_NEED_MDATA)
|
|
rte_security_set_pkt_metadata(
|
|
ips->security.ctx, ips->security.ses,
|
|
pkts[i], NULL);
|
|
continue;
|
|
}
|
|
|
|
RTE_ASSERT(sa->cdev_id_qp < ipsec_ctx->nb_qps);
|
|
enqueue_cop(&ipsec_ctx->tbl[sa->cdev_id_qp], &priv->cop);
|
|
}
|
|
}
|
|
|
|
static inline int32_t
|
|
ipsec_inline_dequeue(ipsec_xform_fn xform_func, struct ipsec_ctx *ipsec_ctx,
|
|
struct rte_mbuf *pkts[], uint16_t max_pkts)
|
|
{
|
|
int32_t nb_pkts, ret;
|
|
struct ipsec_mbuf_metadata *priv;
|
|
struct ipsec_sa *sa;
|
|
struct rte_mbuf *pkt;
|
|
|
|
nb_pkts = 0;
|
|
while (ipsec_ctx->ol_pkts_cnt > 0 && nb_pkts < max_pkts) {
|
|
pkt = ipsec_ctx->ol_pkts[--ipsec_ctx->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;
|
|
}
|
|
|
|
return nb_pkts;
|
|
}
|
|
|
|
static inline int
|
|
ipsec_dequeue(ipsec_xform_fn xform_func, struct ipsec_ctx *ipsec_ctx,
|
|
struct rte_mbuf *pkts[], uint16_t max_pkts)
|
|
{
|
|
int32_t nb_pkts = 0, ret = 0, i, j, nb_cops;
|
|
struct ipsec_mbuf_metadata *priv;
|
|
struct rte_crypto_op *cops[max_pkts];
|
|
struct ipsec_sa *sa;
|
|
struct rte_mbuf *pkt;
|
|
|
|
for (i = 0; i < ipsec_ctx->nb_qps && nb_pkts < max_pkts; i++) {
|
|
struct cdev_qp *cqp;
|
|
|
|
cqp = &ipsec_ctx->tbl[ipsec_ctx->last_qp++];
|
|
if (ipsec_ctx->last_qp == ipsec_ctx->nb_qps)
|
|
ipsec_ctx->last_qp %= ipsec_ctx->nb_qps;
|
|
|
|
if (cqp->in_flight == 0)
|
|
continue;
|
|
|
|
nb_cops = rte_cryptodev_dequeue_burst(cqp->id, cqp->qp,
|
|
cops, max_pkts - nb_pkts);
|
|
|
|
cqp->in_flight -= nb_cops;
|
|
|
|
for (j = 0; j < nb_cops; j++) {
|
|
pkt = cops[j]->sym->m_src;
|
|
rte_prefetch0(pkt);
|
|
|
|
priv = get_priv(pkt);
|
|
sa = priv->sa;
|
|
|
|
RTE_ASSERT(sa != NULL);
|
|
|
|
if (ipsec_get_action_type(sa) ==
|
|
RTE_SECURITY_ACTION_TYPE_NONE) {
|
|
ret = xform_func(pkt, sa, cops[j]);
|
|
if (unlikely(ret)) {
|
|
rte_pktmbuf_free(pkt);
|
|
continue;
|
|
}
|
|
} else if (ipsec_get_action_type(sa) ==
|
|
RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL) {
|
|
if (cops[j]->status) {
|
|
rte_pktmbuf_free(pkt);
|
|
continue;
|
|
}
|
|
}
|
|
pkts[nb_pkts++] = pkt;
|
|
}
|
|
}
|
|
|
|
/* return packets */
|
|
return nb_pkts;
|
|
}
|
|
|
|
uint16_t
|
|
ipsec_inbound(struct ipsec_ctx *ctx, struct rte_mbuf *pkts[],
|
|
uint16_t nb_pkts, uint16_t len)
|
|
{
|
|
void *sas[nb_pkts];
|
|
|
|
inbound_sa_lookup(ctx->sa_ctx, pkts, sas, nb_pkts);
|
|
|
|
ipsec_enqueue(esp_inbound, ctx, pkts, sas, nb_pkts);
|
|
|
|
return ipsec_inline_dequeue(esp_inbound_post, ctx, pkts, len);
|
|
}
|
|
|
|
uint16_t
|
|
ipsec_inbound_cqp_dequeue(struct ipsec_ctx *ctx, struct rte_mbuf *pkts[],
|
|
uint16_t len)
|
|
{
|
|
return ipsec_dequeue(esp_inbound_post, ctx, pkts, len);
|
|
}
|
|
|
|
uint16_t
|
|
ipsec_outbound(struct ipsec_ctx *ctx, struct rte_mbuf *pkts[],
|
|
uint32_t sa_idx[], uint16_t nb_pkts, uint16_t len)
|
|
{
|
|
void *sas[nb_pkts];
|
|
|
|
outbound_sa_lookup(ctx->sa_ctx, sa_idx, sas, nb_pkts);
|
|
|
|
ipsec_enqueue(esp_outbound, ctx, pkts, sas, nb_pkts);
|
|
|
|
return ipsec_inline_dequeue(esp_outbound_post, ctx, pkts, len);
|
|
}
|
|
|
|
uint16_t
|
|
ipsec_outbound_cqp_dequeue(struct ipsec_ctx *ctx, struct rte_mbuf *pkts[],
|
|
uint16_t len)
|
|
{
|
|
return ipsec_dequeue(esp_outbound_post, ctx, pkts, len);
|
|
}
|