numam-dpdk/drivers/net/octeontx2/otx2_ethdev_sec.c
Vamsi Attunuru fb9f56f3e3 net/octeontx2: sync inline tag type
Tag type configuration for the inline processed packets is set during
ethdev configuration, it might conflict with tag type configuration
done during Rx adapter configuration which would be setup later.

This conflict is fixed as part of flow rule creation by updating
tag type config of inline same as Rx adapter configured tag type.

Signed-off-by: Ankur Dwivedi <adwivedi@marvell.com>
Signed-off-by: Anoob Joseph <anoobj@marvell.com>
Signed-off-by: Archana Muniganti <marchana@marvell.com>
Signed-off-by: Tejasree Kondoj <ktejasree@marvell.com>
Signed-off-by: Vamsi Attunuru <vattunuru@marvell.com>
Acked-by: Akhil Goyal <akhil.goyal@nxp.com>
2020-02-05 15:20:51 +01:00

845 lines
20 KiB
C

/* SPDX-License-Identifier: BSD-3-Clause
* Copyright (C) 2020 Marvell International Ltd.
*/
#include <rte_cryptodev.h>
#include <rte_esp.h>
#include <rte_ethdev.h>
#include <rte_eventdev.h>
#include <rte_ip.h>
#include <rte_malloc.h>
#include <rte_memzone.h>
#include <rte_security.h>
#include <rte_security_driver.h>
#include <rte_udp.h>
#include "otx2_common.h"
#include "otx2_cryptodev_qp.h"
#include "otx2_ethdev.h"
#include "otx2_ethdev_sec.h"
#include "otx2_ipsec_fp.h"
#include "otx2_sec_idev.h"
#define ETH_SEC_MAX_PKT_LEN 1450
#define AH_HDR_LEN 12
#define AES_GCM_IV_LEN 8
#define AES_GCM_MAC_LEN 16
#define AES_CBC_IV_LEN 16
#define SHA1_HMAC_LEN 12
#define AES_GCM_ROUNDUP_BYTE_LEN 4
#define AES_CBC_ROUNDUP_BYTE_LEN 16
struct eth_sec_tag_const {
RTE_STD_C11
union {
struct {
uint32_t rsvd_11_0 : 12;
uint32_t port : 8;
uint32_t event_type : 4;
uint32_t rsvd_31_24 : 8;
};
uint32_t u32;
};
};
static struct rte_cryptodev_capabilities otx2_eth_sec_crypto_caps[] = {
{ /* AES GCM */
.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
{.sym = {
.xform_type = RTE_CRYPTO_SYM_XFORM_AEAD,
{.aead = {
.algo = RTE_CRYPTO_AEAD_AES_GCM,
.block_size = 16,
.key_size = {
.min = 16,
.max = 32,
.increment = 8
},
.digest_size = {
.min = 16,
.max = 16,
.increment = 0
},
.aad_size = {
.min = 8,
.max = 12,
.increment = 4
},
.iv_size = {
.min = 12,
.max = 12,
.increment = 0
}
}, }
}, }
},
{ /* AES CBC */
.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
{.sym = {
.xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER,
{.cipher = {
.algo = RTE_CRYPTO_CIPHER_AES_CBC,
.block_size = 16,
.key_size = {
.min = 16,
.max = 32,
.increment = 8
},
.iv_size = {
.min = 16,
.max = 16,
.increment = 0
}
}, }
}, }
},
{ /* SHA1 HMAC */
.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
{.sym = {
.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
{.auth = {
.algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
.block_size = 64,
.key_size = {
.min = 20,
.max = 64,
.increment = 1
},
.digest_size = {
.min = 12,
.max = 12,
.increment = 0
},
}, }
}, }
},
RTE_CRYPTODEV_END_OF_CAPABILITIES_LIST()
};
static const struct rte_security_capability otx2_eth_sec_capabilities[] = {
{ /* IPsec Inline Protocol ESP Tunnel Ingress */
.action = RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL,
.protocol = RTE_SECURITY_PROTOCOL_IPSEC,
.ipsec = {
.proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP,
.mode = RTE_SECURITY_IPSEC_SA_MODE_TUNNEL,
.direction = RTE_SECURITY_IPSEC_SA_DIR_INGRESS,
.options = { 0 }
},
.crypto_capabilities = otx2_eth_sec_crypto_caps,
.ol_flags = RTE_SECURITY_TX_OLOAD_NEED_MDATA
},
{ /* IPsec Inline Protocol ESP Tunnel Egress */
.action = RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL,
.protocol = RTE_SECURITY_PROTOCOL_IPSEC,
.ipsec = {
.proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP,
.mode = RTE_SECURITY_IPSEC_SA_MODE_TUNNEL,
.direction = RTE_SECURITY_IPSEC_SA_DIR_EGRESS,
.options = { 0 }
},
.crypto_capabilities = otx2_eth_sec_crypto_caps,
.ol_flags = RTE_SECURITY_TX_OLOAD_NEED_MDATA
},
{
.action = RTE_SECURITY_ACTION_TYPE_NONE
}
};
static void
lookup_mem_sa_tbl_clear(struct rte_eth_dev *eth_dev)
{
static const char name[] = OTX2_NIX_FASTPATH_LOOKUP_MEM;
uint16_t port = eth_dev->data->port_id;
const struct rte_memzone *mz;
uint64_t **sa_tbl;
uint8_t *mem;
mz = rte_memzone_lookup(name);
if (mz == NULL)
return;
mem = mz->addr;
sa_tbl = (uint64_t **)RTE_PTR_ADD(mem, OTX2_NIX_SA_TBL_START);
if (sa_tbl[port] == NULL)
return;
rte_free(sa_tbl[port]);
sa_tbl[port] = NULL;
}
static int
lookup_mem_sa_index_update(struct rte_eth_dev *eth_dev, int spi, void *sa)
{
static const char name[] = OTX2_NIX_FASTPATH_LOOKUP_MEM;
struct otx2_eth_dev *dev = otx2_eth_pmd_priv(eth_dev);
uint16_t port = eth_dev->data->port_id;
const struct rte_memzone *mz;
uint64_t **sa_tbl;
uint8_t *mem;
mz = rte_memzone_lookup(name);
if (mz == NULL) {
otx2_err("Could not find fastpath lookup table");
return -EINVAL;
}
mem = mz->addr;
sa_tbl = (uint64_t **)RTE_PTR_ADD(mem, OTX2_NIX_SA_TBL_START);
if (sa_tbl[port] == NULL) {
sa_tbl[port] = rte_malloc(NULL, dev->ipsec_in_max_spi *
sizeof(uint64_t), 0);
}
sa_tbl[port][spi] = (uint64_t)sa;
return 0;
}
static inline void
in_sa_mz_name_get(char *name, int size, uint16_t port)
{
snprintf(name, size, "otx2_ipsec_in_sadb_%u", port);
}
static struct otx2_ipsec_fp_in_sa *
in_sa_get(uint16_t port, int sa_index)
{
char name[RTE_MEMZONE_NAMESIZE];
struct otx2_ipsec_fp_in_sa *sa;
const struct rte_memzone *mz;
in_sa_mz_name_get(name, RTE_MEMZONE_NAMESIZE, port);
mz = rte_memzone_lookup(name);
if (mz == NULL) {
otx2_err("Could not get the memzone reserved for IN SA DB");
return NULL;
}
sa = mz->addr;
return sa + sa_index;
}
static int
ipsec_sa_const_set(struct rte_security_ipsec_xform *ipsec,
struct rte_crypto_sym_xform *xform,
struct otx2_sec_session_ipsec_ip *sess)
{
struct rte_crypto_sym_xform *cipher_xform, *auth_xform;
sess->partial_len = sizeof(struct rte_ipv4_hdr);
if (ipsec->proto == RTE_SECURITY_IPSEC_SA_PROTO_ESP) {
sess->partial_len += sizeof(struct rte_esp_hdr);
sess->roundup_len = sizeof(struct rte_esp_tail);
} else if (ipsec->proto == RTE_SECURITY_IPSEC_SA_PROTO_AH) {
sess->partial_len += AH_HDR_LEN;
} else {
return -EINVAL;
}
if (ipsec->options.udp_encap)
sess->partial_len += sizeof(struct rte_udp_hdr);
if (xform->type == RTE_CRYPTO_SYM_XFORM_AEAD) {
if (xform->aead.algo == RTE_CRYPTO_AEAD_AES_GCM) {
sess->partial_len += AES_GCM_IV_LEN;
sess->partial_len += AES_GCM_MAC_LEN;
sess->roundup_byte = AES_GCM_ROUNDUP_BYTE_LEN;
}
return 0;
}
if (ipsec->direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS) {
cipher_xform = xform;
auth_xform = xform->next;
} else if (ipsec->direction == RTE_SECURITY_IPSEC_SA_DIR_INGRESS) {
auth_xform = xform;
cipher_xform = xform->next;
} else {
return -EINVAL;
}
if (cipher_xform->cipher.algo == RTE_CRYPTO_CIPHER_AES_CBC) {
sess->partial_len += AES_CBC_IV_LEN;
sess->roundup_byte = AES_CBC_ROUNDUP_BYTE_LEN;
} else {
return -EINVAL;
}
if (auth_xform->auth.algo == RTE_CRYPTO_AUTH_SHA1_HMAC)
sess->partial_len += SHA1_HMAC_LEN;
else
return -EINVAL;
return 0;
}
static int
hmac_init(struct otx2_ipsec_fp_sa_ctl *ctl, struct otx2_cpt_qp *qp,
const uint8_t *auth_key, int len, uint8_t *hmac_key)
{
struct inst_data {
struct otx2_cpt_res cpt_res;
uint8_t buffer[64];
} *md;
volatile struct otx2_cpt_res *res;
uint64_t timeout, lmt_status;
struct otx2_cpt_inst_s inst;
rte_iova_t md_iova;
int ret;
memset(&inst, 0, sizeof(struct otx2_cpt_inst_s));
md = rte_zmalloc(NULL, sizeof(struct inst_data), OTX2_CPT_RES_ALIGN);
if (md == NULL)
return -ENOMEM;
memcpy(md->buffer, auth_key, len);
md_iova = rte_malloc_virt2iova(md);
if (md_iova == RTE_BAD_IOVA) {
ret = -EINVAL;
goto free_md;
}
inst.res_addr = md_iova + offsetof(struct inst_data, cpt_res);
inst.opcode = OTX2_CPT_OP_WRITE_HMAC_IPAD_OPAD;
inst.param2 = ctl->auth_type;
inst.dlen = len;
inst.dptr = md_iova + offsetof(struct inst_data, buffer);
inst.rptr = inst.dptr;
inst.egrp = OTX2_CPT_EGRP_INLINE_IPSEC;
md->cpt_res.compcode = 0;
md->cpt_res.uc_compcode = 0xff;
timeout = rte_get_timer_cycles() + 5 * rte_get_timer_hz();
rte_cio_wmb();
do {
otx2_lmt_mov(qp->lmtline, &inst, 2);
lmt_status = otx2_lmt_submit(qp->lf_nq_reg);
} while (lmt_status == 0);
res = (volatile struct otx2_cpt_res *)&md->cpt_res;
/* Wait until instruction completes or times out */
while (res->uc_compcode == 0xff) {
if (rte_get_timer_cycles() > timeout)
break;
}
if (res->u16[0] != OTX2_SEC_COMP_GOOD) {
ret = -EIO;
goto free_md;
}
/* Retrieve the ipad and opad from rptr */
memcpy(hmac_key, md->buffer, 48);
ret = 0;
free_md:
rte_free(md);
return ret;
}
static int
eth_sec_ipsec_out_sess_create(struct rte_eth_dev *eth_dev,
struct rte_security_ipsec_xform *ipsec,
struct rte_crypto_sym_xform *crypto_xform,
struct rte_security_session *sec_sess)
{
struct rte_crypto_sym_xform *auth_xform, *cipher_xform;
struct otx2_sec_session_ipsec_ip *sess;
uint16_t port = eth_dev->data->port_id;
int cipher_key_len, auth_key_len, ret;
const uint8_t *cipher_key, *auth_key;
struct otx2_ipsec_fp_sa_ctl *ctl;
struct otx2_ipsec_fp_out_sa *sa;
struct otx2_sec_session *priv;
struct otx2_cpt_inst_s inst;
struct otx2_cpt_qp *qp;
priv = get_sec_session_private_data(sec_sess);
sess = &priv->ipsec.ip;
sa = &sess->out_sa;
ctl = &sa->ctl;
if (ctl->valid) {
otx2_err("SA already registered");
return -EINVAL;
}
memset(sess, 0, sizeof(struct otx2_sec_session_ipsec_ip));
sess->seq = 1;
ret = ipsec_sa_const_set(ipsec, crypto_xform, sess);
if (ret < 0)
return ret;
if (crypto_xform->type == RTE_CRYPTO_SYM_XFORM_AEAD)
memcpy(sa->nonce, &ipsec->salt, 4);
if (ipsec->options.udp_encap == 1) {
sa->udp_src = 4500;
sa->udp_dst = 4500;
}
if (ipsec->mode == RTE_SECURITY_IPSEC_SA_MODE_TUNNEL) {
/* Start ip id from 1 */
sess->ip_id = 1;
if (ipsec->tunnel.type == RTE_SECURITY_IPSEC_TUNNEL_IPV4) {
memcpy(&sa->ip_src, &ipsec->tunnel.ipv4.src_ip,
sizeof(struct in_addr));
memcpy(&sa->ip_dst, &ipsec->tunnel.ipv4.dst_ip,
sizeof(struct in_addr));
} else {
return -EINVAL;
}
} else {
return -EINVAL;
}
cipher_xform = crypto_xform;
auth_xform = crypto_xform->next;
cipher_key_len = 0;
auth_key_len = 0;
auth_key = NULL;
if (crypto_xform->type == RTE_CRYPTO_SYM_XFORM_AEAD) {
cipher_key = crypto_xform->aead.key.data;
cipher_key_len = crypto_xform->aead.key.length;
} else {
cipher_key = cipher_xform->cipher.key.data;
cipher_key_len = cipher_xform->cipher.key.length;
auth_key = auth_xform->auth.key.data;
auth_key_len = auth_xform->auth.key.length;
}
if (cipher_key_len != 0)
memcpy(sa->cipher_key, cipher_key, cipher_key_len);
else
return -EINVAL;
/* Determine word 7 of CPT instruction */
inst.u64[7] = 0;
inst.egrp = OTX2_CPT_EGRP_INLINE_IPSEC;
inst.cptr = rte_mempool_virt2iova(sa);
sess->inst_w7 = inst.u64[7];
/* Get CPT QP to be used for this SA */
ret = otx2_sec_idev_tx_cpt_qp_get(port, &qp);
if (ret)
return ret;
sess->qp = qp;
sess->cpt_lmtline = qp->lmtline;
sess->cpt_nq_reg = qp->lf_nq_reg;
/* Populate control word */
ret = ipsec_fp_sa_ctl_set(ipsec, crypto_xform, ctl);
if (ret)
goto cpt_put;
if (auth_key_len && auth_key) {
ret = hmac_init(ctl, qp, auth_key, auth_key_len, sa->hmac_key);
if (ret)
goto cpt_put;
}
return 0;
cpt_put:
otx2_sec_idev_tx_cpt_qp_put(sess->qp);
return ret;
}
static int
eth_sec_ipsec_in_sess_create(struct rte_eth_dev *eth_dev,
struct rte_security_ipsec_xform *ipsec,
struct rte_crypto_sym_xform *crypto_xform,
struct rte_security_session *sec_sess)
{
struct rte_crypto_sym_xform *auth_xform, *cipher_xform;
struct otx2_eth_dev *dev = otx2_eth_pmd_priv(eth_dev);
struct otx2_sec_session_ipsec_ip *sess;
uint16_t port = eth_dev->data->port_id;
int cipher_key_len, auth_key_len, ret;
const uint8_t *cipher_key, *auth_key;
struct otx2_ipsec_fp_sa_ctl *ctl;
struct otx2_ipsec_fp_in_sa *sa;
struct otx2_sec_session *priv;
struct otx2_cpt_qp *qp;
if (ipsec->spi >= dev->ipsec_in_max_spi) {
otx2_err("SPI exceeds max supported");
return -EINVAL;
}
sa = in_sa_get(port, ipsec->spi);
ctl = &sa->ctl;
priv = get_sec_session_private_data(sec_sess);
sess = &priv->ipsec.ip;
if (ctl->valid) {
otx2_err("SA already registered");
return -EINVAL;
}
memset(sa, 0, sizeof(struct otx2_ipsec_fp_in_sa));
auth_xform = crypto_xform;
cipher_xform = crypto_xform->next;
cipher_key_len = 0;
auth_key_len = 0;
auth_key = NULL;
if (crypto_xform->type == RTE_CRYPTO_SYM_XFORM_AEAD) {
if (crypto_xform->aead.algo == RTE_CRYPTO_AEAD_AES_GCM)
memcpy(sa->nonce, &ipsec->salt, 4);
cipher_key = crypto_xform->aead.key.data;
cipher_key_len = crypto_xform->aead.key.length;
} else {
cipher_key = cipher_xform->cipher.key.data;
cipher_key_len = cipher_xform->cipher.key.length;
auth_key = auth_xform->auth.key.data;
auth_key_len = auth_xform->auth.key.length;
}
if (cipher_key_len != 0)
memcpy(sa->cipher_key, cipher_key, cipher_key_len);
else
return -EINVAL;
sess->in_sa = sa;
sa->userdata = priv->userdata;
if (lookup_mem_sa_index_update(eth_dev, ipsec->spi, sa))
return -EINVAL;
ret = ipsec_fp_sa_ctl_set(ipsec, crypto_xform, ctl);
if (ret)
return ret;
if (auth_key_len && auth_key) {
/* Get a queue pair for HMAC init */
ret = otx2_sec_idev_tx_cpt_qp_get(port, &qp);
if (ret)
return ret;
ret = hmac_init(ctl, qp, auth_key, auth_key_len, sa->hmac_key);
otx2_sec_idev_tx_cpt_qp_put(qp);
}
return ret;
}
static int
eth_sec_ipsec_sess_create(struct rte_eth_dev *eth_dev,
struct rte_security_ipsec_xform *ipsec,
struct rte_crypto_sym_xform *crypto_xform,
struct rte_security_session *sess)
{
int ret;
ret = ipsec_fp_xform_verify(ipsec, crypto_xform);
if (ret)
return ret;
if (ipsec->direction == RTE_SECURITY_IPSEC_SA_DIR_INGRESS)
return eth_sec_ipsec_in_sess_create(eth_dev, ipsec,
crypto_xform, sess);
else
return eth_sec_ipsec_out_sess_create(eth_dev, ipsec,
crypto_xform, sess);
}
static int
otx2_eth_sec_session_create(void *device,
struct rte_security_session_conf *conf,
struct rte_security_session *sess,
struct rte_mempool *mempool)
{
struct otx2_sec_session *priv;
int ret;
if (conf->action_type != RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL)
return -ENOTSUP;
if (rte_mempool_get(mempool, (void **)&priv)) {
otx2_err("Could not allocate security session private data");
return -ENOMEM;
}
set_sec_session_private_data(sess, priv);
/*
* Save userdata provided by the application. For ingress packets, this
* could be used to identify the SA.
*/
priv->userdata = conf->userdata;
if (conf->protocol == RTE_SECURITY_PROTOCOL_IPSEC)
ret = eth_sec_ipsec_sess_create(device, &conf->ipsec,
conf->crypto_xform,
sess);
else
ret = -ENOTSUP;
if (ret)
goto mempool_put;
return 0;
mempool_put:
rte_mempool_put(mempool, priv);
set_sec_session_private_data(sess, NULL);
return ret;
}
static int
otx2_eth_sec_session_destroy(void *device __rte_unused,
struct rte_security_session *sess)
{
struct otx2_sec_session_ipsec_ip *sess_ip;
struct otx2_sec_session *priv;
struct rte_mempool *sess_mp;
int ret;
priv = get_sec_session_private_data(sess);
if (priv == NULL)
return -EINVAL;
sess_ip = &priv->ipsec.ip;
/* Release CPT LF used for this session */
if (sess_ip->qp != NULL) {
ret = otx2_sec_idev_tx_cpt_qp_put(sess_ip->qp);
if (ret)
return ret;
}
sess_mp = rte_mempool_from_obj(priv);
set_sec_session_private_data(sess, NULL);
rte_mempool_put(sess_mp, priv);
return 0;
}
static unsigned int
otx2_eth_sec_session_get_size(void *device __rte_unused)
{
return sizeof(struct otx2_sec_session);
}
static int
otx2_eth_sec_set_pkt_mdata(void *device __rte_unused,
struct rte_security_session *session,
struct rte_mbuf *m, void *params __rte_unused)
{
/* Set security session as the pkt metadata */
m->udata64 = (uint64_t)session;
return 0;
}
static int
otx2_eth_sec_get_userdata(void *device __rte_unused, uint64_t md,
void **userdata)
{
/* Retrieve userdata */
*userdata = (void *)md;
return 0;
}
static const struct rte_security_capability *
otx2_eth_sec_capabilities_get(void *device __rte_unused)
{
return otx2_eth_sec_capabilities;
}
static struct rte_security_ops otx2_eth_sec_ops = {
.session_create = otx2_eth_sec_session_create,
.session_destroy = otx2_eth_sec_session_destroy,
.session_get_size = otx2_eth_sec_session_get_size,
.set_pkt_metadata = otx2_eth_sec_set_pkt_mdata,
.get_userdata = otx2_eth_sec_get_userdata,
.capabilities_get = otx2_eth_sec_capabilities_get
};
int
otx2_eth_sec_ctx_create(struct rte_eth_dev *eth_dev)
{
struct rte_security_ctx *ctx;
int ret;
ctx = rte_malloc("otx2_eth_sec_ctx",
sizeof(struct rte_security_ctx), 0);
if (ctx == NULL)
return -ENOMEM;
ret = otx2_sec_idev_cfg_init(eth_dev->data->port_id);
if (ret) {
rte_free(ctx);
return ret;
}
/* Populate ctx */
ctx->device = eth_dev;
ctx->ops = &otx2_eth_sec_ops;
ctx->sess_cnt = 0;
eth_dev->security_ctx = ctx;
return 0;
}
void
otx2_eth_sec_ctx_destroy(struct rte_eth_dev *eth_dev)
{
rte_free(eth_dev->security_ctx);
}
static int
eth_sec_ipsec_cfg(struct rte_eth_dev *eth_dev, uint8_t tt)
{
struct otx2_eth_dev *dev = otx2_eth_pmd_priv(eth_dev);
uint16_t port = eth_dev->data->port_id;
struct nix_inline_ipsec_lf_cfg *req;
struct otx2_mbox *mbox = dev->mbox;
struct eth_sec_tag_const tag_const;
char name[RTE_MEMZONE_NAMESIZE];
const struct rte_memzone *mz;
in_sa_mz_name_get(name, RTE_MEMZONE_NAMESIZE, port);
mz = rte_memzone_lookup(name);
if (mz == NULL)
return -EINVAL;
req = otx2_mbox_alloc_msg_nix_inline_ipsec_lf_cfg(mbox);
req->enable = 1;
req->sa_base_addr = mz->iova;
req->ipsec_cfg0.tt = tt;
tag_const.u32 = 0;
tag_const.event_type = RTE_EVENT_TYPE_ETHDEV;
tag_const.port = port;
req->ipsec_cfg0.tag_const = tag_const.u32;
req->ipsec_cfg0.sa_pow2_size =
rte_log2_u32(sizeof(struct otx2_ipsec_fp_in_sa));
req->ipsec_cfg0.lenm1_max = ETH_SEC_MAX_PKT_LEN - 1;
req->ipsec_cfg1.sa_idx_w = rte_log2_u32(dev->ipsec_in_max_spi);
req->ipsec_cfg1.sa_idx_max = dev->ipsec_in_max_spi - 1;
return otx2_mbox_process(mbox);
}
int
otx2_eth_sec_update_tag_type(struct rte_eth_dev *eth_dev)
{
struct otx2_eth_dev *dev = otx2_eth_pmd_priv(eth_dev);
struct otx2_mbox *mbox = dev->mbox;
struct nix_aq_enq_rsp *rsp;
struct nix_aq_enq_req *aq;
int ret;
aq = otx2_mbox_alloc_msg_nix_aq_enq(mbox);
aq->qidx = 0; /* Read RQ:0 context */
aq->ctype = NIX_AQ_CTYPE_RQ;
aq->op = NIX_AQ_INSTOP_READ;
ret = otx2_mbox_process_msg(mbox, (void *)&rsp);
if (ret < 0) {
otx2_err("Could not read RQ context");
return ret;
}
/* Update tag type */
ret = eth_sec_ipsec_cfg(eth_dev, rsp->rq.sso_tt);
if (ret < 0)
otx2_err("Could not update sec eth tag type");
return ret;
}
int
otx2_eth_sec_init(struct rte_eth_dev *eth_dev)
{
const size_t sa_width = sizeof(struct otx2_ipsec_fp_in_sa);
struct otx2_eth_dev *dev = otx2_eth_pmd_priv(eth_dev);
uint16_t port = eth_dev->data->port_id;
char name[RTE_MEMZONE_NAMESIZE];
const struct rte_memzone *mz;
int mz_sz, ret;
uint16_t nb_sa;
RTE_BUILD_BUG_ON(sa_width < 32 || sa_width > 512 ||
!RTE_IS_POWER_OF_2(sa_width));
if (!(dev->tx_offloads & DEV_TX_OFFLOAD_SECURITY) &&
!(dev->rx_offloads & DEV_RX_OFFLOAD_SECURITY))
return 0;
nb_sa = dev->ipsec_in_max_spi;
mz_sz = nb_sa * sa_width;
in_sa_mz_name_get(name, RTE_MEMZONE_NAMESIZE, port);
mz = rte_memzone_reserve_aligned(name, mz_sz, rte_socket_id(),
RTE_MEMZONE_IOVA_CONTIG, OTX2_ALIGN);
if (mz == NULL) {
otx2_err("Could not allocate inbound SA DB");
return -ENOMEM;
}
memset(mz->addr, 0, mz_sz);
ret = eth_sec_ipsec_cfg(eth_dev, SSO_TT_ORDERED);
if (ret < 0) {
otx2_err("Could not configure inline IPsec");
goto sec_fini;
}
return 0;
sec_fini:
otx2_err("Could not configure device for security");
otx2_eth_sec_fini(eth_dev);
return ret;
}
void
otx2_eth_sec_fini(struct rte_eth_dev *eth_dev)
{
struct otx2_eth_dev *dev = otx2_eth_pmd_priv(eth_dev);
uint16_t port = eth_dev->data->port_id;
char name[RTE_MEMZONE_NAMESIZE];
if (!(dev->tx_offloads & DEV_TX_OFFLOAD_SECURITY) &&
!(dev->rx_offloads & DEV_RX_OFFLOAD_SECURITY))
return;
lookup_mem_sa_tbl_clear(eth_dev);
in_sa_mz_name_get(name, RTE_MEMZONE_NAMESIZE, port);
rte_memzone_free(rte_memzone_lookup(name));
}