diff --git a/drivers/common/octeontx2/otx2_sec_idev.c b/drivers/common/octeontx2/otx2_sec_idev.c index e9240785f6..4e65ce2a34 100644 --- a/drivers/common/octeontx2/otx2_sec_idev.c +++ b/drivers/common/octeontx2/otx2_sec_idev.c @@ -118,3 +118,66 @@ otx2_sec_idev_tx_cpt_qp_remove(struct otx2_cpt_qp *qp) rte_spinlock_unlock(&cfg->tx_cpt_lock); return ret; } + +int +otx2_sec_idev_tx_cpt_qp_get(uint16_t port_id, struct otx2_cpt_qp **qp) +{ + struct otx2_sec_idev_cfg *cfg; + uint16_t index; + int i, ret; + + if (port_id > OTX2_MAX_INLINE_PORTS || qp == NULL) + return -EINVAL; + + cfg = &sec_cfg[port_id]; + + rte_spinlock_lock(&cfg->tx_cpt_lock); + + index = cfg->tx_cpt_idx; + + /* Get the next index with valid data */ + for (i = 0; i < OTX2_MAX_CPT_QP_PER_PORT; i++) { + if (cfg->tx_cpt[index].qp != NULL) + break; + index = (index + 1) % OTX2_MAX_CPT_QP_PER_PORT; + } + + if (i >= OTX2_MAX_CPT_QP_PER_PORT) { + ret = -EINVAL; + goto unlock; + } + + *qp = cfg->tx_cpt[index].qp; + rte_atomic16_inc(&cfg->tx_cpt[index].ref_cnt); + + cfg->tx_cpt_idx = (index + 1) % OTX2_MAX_CPT_QP_PER_PORT; + + ret = 0; + +unlock: + rte_spinlock_unlock(&cfg->tx_cpt_lock); + return ret; +} + +int +otx2_sec_idev_tx_cpt_qp_put(struct otx2_cpt_qp *qp) +{ + struct otx2_sec_idev_cfg *cfg; + uint16_t port_id; + int i; + + if (qp == NULL) + return -EINVAL; + + for (port_id = 0; port_id < OTX2_MAX_INLINE_PORTS; port_id++) { + cfg = &sec_cfg[port_id]; + for (i = 0; i < OTX2_MAX_CPT_QP_PER_PORT; i++) { + if (cfg->tx_cpt[i].qp == qp) { + rte_atomic16_dec(&cfg->tx_cpt[i].ref_cnt); + return 0; + } + } + } + + return -EINVAL; +} diff --git a/drivers/common/octeontx2/otx2_sec_idev.h b/drivers/common/octeontx2/otx2_sec_idev.h index 20d71d0eb7..c681f50945 100644 --- a/drivers/common/octeontx2/otx2_sec_idev.h +++ b/drivers/common/octeontx2/otx2_sec_idev.h @@ -30,4 +30,8 @@ int otx2_sec_idev_tx_cpt_qp_add(uint16_t port_id, struct otx2_cpt_qp *qp); int otx2_sec_idev_tx_cpt_qp_remove(struct otx2_cpt_qp *qp); +int otx2_sec_idev_tx_cpt_qp_put(struct otx2_cpt_qp *qp); + +int otx2_sec_idev_tx_cpt_qp_get(uint16_t port_id, struct otx2_cpt_qp **qp); + #endif /* _OTX2_SEC_IDEV_H_ */ diff --git a/drivers/common/octeontx2/rte_common_octeontx2_version.map b/drivers/common/octeontx2/rte_common_octeontx2_version.map index 775aca801f..19a7b193b5 100644 --- a/drivers/common/octeontx2/rte_common_octeontx2_version.map +++ b/drivers/common/octeontx2/rte_common_octeontx2_version.map @@ -31,6 +31,8 @@ DPDK_20.0 { otx2_sec_idev_cfg_init; otx2_sec_idev_tx_cpt_qp_add; otx2_sec_idev_tx_cpt_qp_remove; + otx2_sec_idev_tx_cpt_qp_get; + otx2_sec_idev_tx_cpt_qp_put; otx2_sso_pf_func_get; otx2_sso_pf_func_set; otx2_unregister_irq; diff --git a/drivers/crypto/octeontx2/otx2_ipsec_fp.h b/drivers/crypto/octeontx2/otx2_ipsec_fp.h index bf4181ac9b..52b3b41e23 100644 --- a/drivers/crypto/octeontx2/otx2_ipsec_fp.h +++ b/drivers/crypto/octeontx2/otx2_ipsec_fp.h @@ -5,6 +5,67 @@ #ifndef __OTX2_IPSEC_FP_H__ #define __OTX2_IPSEC_FP_H__ +#include +#include + +enum { + OTX2_IPSEC_FP_SA_DIRECTION_INBOUND = 0, + OTX2_IPSEC_FP_SA_DIRECTION_OUTBOUND = 1, +}; + +enum { + OTX2_IPSEC_FP_SA_IP_VERSION_4 = 0, + OTX2_IPSEC_FP_SA_IP_VERSION_6 = 1, +}; + +enum { + OTX2_IPSEC_FP_SA_MODE_TRANSPORT = 0, + OTX2_IPSEC_FP_SA_MODE_TUNNEL = 1, +}; + +enum { + OTX2_IPSEC_FP_SA_PROTOCOL_AH = 0, + OTX2_IPSEC_FP_SA_PROTOCOL_ESP = 1, +}; + +enum { + OTX2_IPSEC_FP_SA_AES_KEY_LEN_128 = 1, + OTX2_IPSEC_FP_SA_AES_KEY_LEN_192 = 2, + OTX2_IPSEC_FP_SA_AES_KEY_LEN_256 = 3, +}; + +enum { + OTX2_IPSEC_FP_SA_ENC_NULL = 0, + OTX2_IPSEC_FP_SA_ENC_DES_CBC = 1, + OTX2_IPSEC_FP_SA_ENC_3DES_CBC = 2, + OTX2_IPSEC_FP_SA_ENC_AES_CBC = 3, + OTX2_IPSEC_FP_SA_ENC_AES_CTR = 4, + OTX2_IPSEC_FP_SA_ENC_AES_GCM = 5, + OTX2_IPSEC_FP_SA_ENC_AES_CCM = 6, +}; + +enum { + OTX2_IPSEC_FP_SA_AUTH_NULL = 0, + OTX2_IPSEC_FP_SA_AUTH_MD5 = 1, + OTX2_IPSEC_FP_SA_AUTH_SHA1 = 2, + OTX2_IPSEC_FP_SA_AUTH_SHA2_224 = 3, + OTX2_IPSEC_FP_SA_AUTH_SHA2_256 = 4, + OTX2_IPSEC_FP_SA_AUTH_SHA2_384 = 5, + OTX2_IPSEC_FP_SA_AUTH_SHA2_512 = 6, + OTX2_IPSEC_FP_SA_AUTH_AES_GMAC = 7, + OTX2_IPSEC_FP_SA_AUTH_AES_XCBC_128 = 8, +}; + +enum { + OTX2_IPSEC_FP_SA_FRAG_POST = 0, + OTX2_IPSEC_FP_SA_FRAG_PRE = 1, +}; + +enum { + OTX2_IPSEC_FP_SA_ENCAP_NONE = 0, + OTX2_IPSEC_FP_SA_ENCAP_UDP = 1, +}; + struct otx2_ipsec_fp_sa_ctl { rte_be32_t spi : 32; uint64_t exp_proto_inter_frag : 8; @@ -24,6 +85,26 @@ struct otx2_ipsec_fp_sa_ctl { uint64_t aes_key_len : 2; }; +struct otx2_ipsec_fp_out_sa { + /* w0 */ + struct otx2_ipsec_fp_sa_ctl ctl; + + /* w1 */ + uint8_t nonce[4]; + uint16_t udp_src; + uint16_t udp_dst; + + /* w2 */ + uint32_t ip_src; + uint32_t ip_dst; + + /* w3-w6 */ + uint8_t cipher_key[32]; + + /* w7-w12 */ + uint8_t hmac_key[48]; +}; + struct otx2_ipsec_fp_in_sa { /* w0 */ struct otx2_ipsec_fp_sa_ctl ctl; @@ -52,4 +133,218 @@ struct otx2_ipsec_fp_in_sa { uint64_t reserved2; }; +static inline int +ipsec_fp_xform_cipher_verify(struct rte_crypto_sym_xform *xform) +{ + if (xform->cipher.algo == RTE_CRYPTO_CIPHER_AES_CBC) { + switch (xform->cipher.key.length) { + case 16: + case 24: + case 32: + break; + default: + return -ENOTSUP; + } + return 0; + } + + return -ENOTSUP; +} + +static inline int +ipsec_fp_xform_auth_verify(struct rte_crypto_sym_xform *xform) +{ + uint16_t keylen = xform->auth.key.length; + + if (xform->auth.algo == RTE_CRYPTO_AUTH_SHA1_HMAC) { + if (keylen >= 20 && keylen <= 64) + return 0; + } + + return -ENOTSUP; +} + +static inline int +ipsec_fp_xform_aead_verify(struct rte_security_ipsec_xform *ipsec, + struct rte_crypto_sym_xform *xform) +{ + if (ipsec->direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS && + xform->aead.op != RTE_CRYPTO_AEAD_OP_ENCRYPT) + return -EINVAL; + + if (ipsec->direction == RTE_SECURITY_IPSEC_SA_DIR_INGRESS && + xform->aead.op != RTE_CRYPTO_AEAD_OP_DECRYPT) + return -EINVAL; + + if (xform->aead.algo == RTE_CRYPTO_AEAD_AES_GCM) { + switch (xform->aead.key.length) { + case 16: + case 24: + case 32: + break; + default: + return -EINVAL; + } + return 0; + } + + return -ENOTSUP; +} + +static inline int +ipsec_fp_xform_verify(struct rte_security_ipsec_xform *ipsec, + struct rte_crypto_sym_xform *xform) +{ + struct rte_crypto_sym_xform *auth_xform, *cipher_xform; + int ret; + + if (xform->type == RTE_CRYPTO_SYM_XFORM_AEAD) + return ipsec_fp_xform_aead_verify(ipsec, xform); + + if (xform->next == NULL) + return -EINVAL; + + if (ipsec->direction == RTE_SECURITY_IPSEC_SA_DIR_INGRESS) { + /* Ingress */ + if (xform->type != RTE_CRYPTO_SYM_XFORM_AUTH || + xform->next->type != RTE_CRYPTO_SYM_XFORM_CIPHER) + return -EINVAL; + auth_xform = xform; + cipher_xform = xform->next; + } else { + /* Egress */ + if (xform->type != RTE_CRYPTO_SYM_XFORM_CIPHER || + xform->next->type != RTE_CRYPTO_SYM_XFORM_AUTH) + return -EINVAL; + cipher_xform = xform; + auth_xform = xform->next; + } + + ret = ipsec_fp_xform_cipher_verify(cipher_xform); + if (ret) + return ret; + + ret = ipsec_fp_xform_auth_verify(auth_xform); + if (ret) + return ret; + + return 0; +} + +static inline int +ipsec_fp_sa_ctl_set(struct rte_security_ipsec_xform *ipsec, + struct rte_crypto_sym_xform *xform, + struct otx2_ipsec_fp_sa_ctl *ctl) +{ + struct rte_crypto_sym_xform *cipher_xform, *auth_xform; + int aes_key_len; + + if (ipsec->direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS) { + ctl->direction = OTX2_IPSEC_FP_SA_DIRECTION_OUTBOUND; + cipher_xform = xform; + auth_xform = xform->next; + } else if (ipsec->direction == RTE_SECURITY_IPSEC_SA_DIR_INGRESS) { + ctl->direction = OTX2_IPSEC_FP_SA_DIRECTION_INBOUND; + auth_xform = xform; + cipher_xform = xform->next; + } else { + return -EINVAL; + } + + if (ipsec->mode == RTE_SECURITY_IPSEC_SA_MODE_TUNNEL) { + if (ipsec->tunnel.type == RTE_SECURITY_IPSEC_TUNNEL_IPV4) + ctl->outer_ip_ver = OTX2_IPSEC_FP_SA_IP_VERSION_4; + else if (ipsec->tunnel.type == RTE_SECURITY_IPSEC_TUNNEL_IPV6) + ctl->outer_ip_ver = OTX2_IPSEC_FP_SA_IP_VERSION_6; + else + return -EINVAL; + } + + ctl->inner_ip_ver = OTX2_IPSEC_FP_SA_IP_VERSION_4; + + if (ipsec->mode == RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT) + ctl->ipsec_mode = OTX2_IPSEC_FP_SA_MODE_TRANSPORT; + else if (ipsec->mode == RTE_SECURITY_IPSEC_SA_MODE_TUNNEL) + ctl->ipsec_mode = OTX2_IPSEC_FP_SA_MODE_TUNNEL; + else + return -EINVAL; + + if (ipsec->proto == RTE_SECURITY_IPSEC_SA_PROTO_AH) + ctl->ipsec_proto = OTX2_IPSEC_FP_SA_PROTOCOL_AH; + else if (ipsec->proto == RTE_SECURITY_IPSEC_SA_PROTO_ESP) + ctl->ipsec_proto = OTX2_IPSEC_FP_SA_PROTOCOL_ESP; + else + return -EINVAL; + + if (xform->type == RTE_CRYPTO_SYM_XFORM_AEAD) { + if (xform->aead.algo == RTE_CRYPTO_AEAD_AES_GCM) { + ctl->enc_type = OTX2_IPSEC_FP_SA_ENC_AES_GCM; + aes_key_len = xform->aead.key.length; + } else { + return -ENOTSUP; + } + } else if (cipher_xform->cipher.algo == RTE_CRYPTO_CIPHER_AES_CBC) { + ctl->enc_type = OTX2_IPSEC_FP_SA_ENC_AES_CBC; + aes_key_len = cipher_xform->cipher.key.length; + } else { + return -ENOTSUP; + } + + switch (aes_key_len) { + case 16: + ctl->aes_key_len = OTX2_IPSEC_FP_SA_AES_KEY_LEN_128; + break; + case 24: + ctl->aes_key_len = OTX2_IPSEC_FP_SA_AES_KEY_LEN_192; + break; + case 32: + ctl->aes_key_len = OTX2_IPSEC_FP_SA_AES_KEY_LEN_256; + break; + default: + return -EINVAL; + } + + if (xform->type != RTE_CRYPTO_SYM_XFORM_AEAD) { + switch (auth_xform->auth.algo) { + case RTE_CRYPTO_AUTH_NULL: + ctl->auth_type = OTX2_IPSEC_FP_SA_AUTH_NULL; + break; + case RTE_CRYPTO_AUTH_MD5_HMAC: + ctl->auth_type = OTX2_IPSEC_FP_SA_AUTH_MD5; + break; + case RTE_CRYPTO_AUTH_SHA1_HMAC: + ctl->auth_type = OTX2_IPSEC_FP_SA_AUTH_SHA1; + break; + case RTE_CRYPTO_AUTH_SHA224_HMAC: + ctl->auth_type = OTX2_IPSEC_FP_SA_AUTH_SHA2_224; + break; + case RTE_CRYPTO_AUTH_SHA256_HMAC: + ctl->auth_type = OTX2_IPSEC_FP_SA_AUTH_SHA2_256; + break; + case RTE_CRYPTO_AUTH_SHA384_HMAC: + ctl->auth_type = OTX2_IPSEC_FP_SA_AUTH_SHA2_384; + break; + case RTE_CRYPTO_AUTH_SHA512_HMAC: + ctl->auth_type = OTX2_IPSEC_FP_SA_AUTH_SHA2_512; + break; + case RTE_CRYPTO_AUTH_AES_GMAC: + ctl->auth_type = OTX2_IPSEC_FP_SA_AUTH_AES_GMAC; + break; + case RTE_CRYPTO_AUTH_AES_XCBC_MAC: + ctl->auth_type = OTX2_IPSEC_FP_SA_AUTH_AES_XCBC_128; + break; + default: + return -ENOTSUP; + } + } + + if (ipsec->options.esn == 1) + ctl->esn_en = 1; + + ctl->spi = rte_cpu_to_be_32(ipsec->spi); + ctl->valid = 1; + + return 0; +} + #endif /* __OTX2_IPSEC_FP_H__ */ diff --git a/drivers/net/octeontx2/otx2_ethdev_sec.c b/drivers/net/octeontx2/otx2_ethdev_sec.c index 885904269a..2ec2598ac6 100644 --- a/drivers/net/octeontx2/otx2_ethdev_sec.c +++ b/drivers/net/octeontx2/otx2_ethdev_sec.c @@ -141,6 +141,366 @@ 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 +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_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)); + + 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) { + 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; + + /* 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; + + 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) { @@ -154,6 +514,8 @@ otx2_eth_sec_capabilities_get(void *device __rte_unused) } 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, .capabilities_get = otx2_eth_sec_capabilities_get }; diff --git a/drivers/net/octeontx2/otx2_ethdev_sec.h b/drivers/net/octeontx2/otx2_ethdev_sec.h index 8bdc9f0d85..87342ef703 100644 --- a/drivers/net/octeontx2/otx2_ethdev_sec.h +++ b/drivers/net/octeontx2/otx2_ethdev_sec.h @@ -9,12 +9,92 @@ #include "otx2_ipsec_fp.h" +#define OTX2_CPT_RES_ALIGN 16 + +#define OTX2_CPT_EGRP_INLINE_IPSEC 1 + +#define OTX2_CPT_OP_WRITE_HMAC_IPAD_OPAD (0x40 | 0x27) + +#define OTX2_SEC_CPT_COMP_GOOD 0x1 +#define OTX2_SEC_UC_COMP_GOOD 0x0 +#define OTX2_SEC_COMP_GOOD (OTX2_SEC_UC_COMP_GOOD << 8 | \ + OTX2_SEC_CPT_COMP_GOOD) + +/* CPT Result */ +struct otx2_cpt_res { + union { + struct { + uint64_t compcode:8; + uint64_t uc_compcode:8; + uint64_t doneint:1; + uint64_t reserved_17_63:47; + uint64_t reserved_64_127; + }; + uint16_t u16[8]; + }; +}; + +struct otx2_cpt_inst_s { + union { + struct { + /* W0 */ + uint64_t nixtxl : 3; + uint64_t doneint : 1; + uint64_t nixtx_addr : 60; + /* W1 */ + uint64_t res_addr : 64; + /* W2 */ + uint64_t tag : 32; + uint64_t tt : 2; + uint64_t grp : 10; + uint64_t rsvd_175_172 : 4; + uint64_t rvu_pf_func : 16; + /* W3 */ + uint64_t qord : 1; + uint64_t rsvd_194_193 : 2; + uint64_t wqe_ptr : 61; + /* W4 */ + uint64_t dlen : 16; + uint64_t param2 : 16; + uint64_t param1 : 16; + uint64_t opcode : 16; + /* W5 */ + uint64_t dptr : 64; + /* W6 */ + uint64_t rptr : 64; + /* W7 */ + uint64_t cptr : 61; + uint64_t egrp : 3; + }; + uint64_t u64[8]; + }; +}; + /* * Security session for inline IPsec protocol offload. This is private data of * inline capable PMD. */ struct otx2_sec_session_ipsec_ip { - int dummy; + RTE_STD_C11 + union { + /* + * Inbound SA would accessed by crypto block. And so the memory + * is allocated differently and shared with the h/w. Only + * holding a pointer to this memory in the session private + * space. + */ + void *in_sa; + /* Outbound SA */ + struct otx2_ipsec_fp_out_sa out_sa; + }; + + /* Address of CPT LMTLINE */ + void *cpt_lmtline; + /* CPT LF enqueue register address */ + rte_iova_t cpt_nq_reg; + + /* CPT QP used by SA */ + struct otx2_cpt_qp *qp; }; struct otx2_sec_session_ipsec { @@ -23,6 +103,8 @@ struct otx2_sec_session_ipsec { struct otx2_sec_session { struct otx2_sec_session_ipsec ipsec; + void *userdata; + /**< Userdata registered by the application */ } __rte_cache_aligned; int otx2_eth_sec_ctx_create(struct rte_eth_dev *eth_dev);