From: Simon Horman <horms@kernel.org>
To: Bharat Bhushan <bbhushan2@marvell.com>
Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
sgoutham@marvell.com, gakula@marvell.com, sbhatta@marvell.com,
hkelam@marvell.com, davem@davemloft.net, edumazet@google.com,
kuba@kernel.org, pabeni@redhat.com, jerinj@marvell.com,
lcherian@marvell.com, richardcochran@gmail.com
Subject: Re: [net-next,v2 5/8] cn10k-ipsec: Add SA add/delete support for outb inline ipsec
Date: Mon, 13 May 2024 17:51:33 +0100 [thread overview]
Message-ID: <20240513165133.GS2787@kernel.org> (raw)
In-Reply-To: <20240513105446.297451-6-bbhushan2@marvell.com>
On Mon, May 13, 2024 at 04:24:43PM +0530, Bharat Bhushan wrote:
> This patch adds support to add and delete Security Association
> (SA) xfrm ops. Hardware maintains SA context in memory allocated
> by software. Each SA context is 128 byte aligned and size of
> each context is multiple of 128-byte. Add support for transport
> and tunnel ipsec mode, ESP protocol, aead aes-gcm-icv16, key size
> 128/192/256-bits with 32bit salt.
>
> Signed-off-by: Bharat Bhushan <bbhushan2@marvell.com>
> ---
> v1->v2:
> - Use dma_wmb() instead of architecture specific barrier
>
> .../marvell/octeontx2/nic/cn10k_ipsec.c | 433 +++++++++++++++++-
> .../marvell/octeontx2/nic/cn10k_ipsec.h | 114 +++++
> 2 files changed, 546 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/cn10k_ipsec.c b/drivers/net/ethernet/marvell/octeontx2/nic/cn10k_ipsec.c
...
> @@ -356,6 +362,414 @@ static int cn10k_outb_cpt_clean(struct otx2_nic *pf)
> return err;
> }
>
> +static int cn10k_outb_get_sa_index(struct otx2_nic *pf,
> + struct cn10k_tx_sa_s *sa_entry)
> +{
> + u32 sa_size = pf->ipsec.sa_size;
> + u32 sa_index;
> +
> + if (!sa_entry || ((void *)sa_entry < pf->ipsec.outb_sa->base))
> + return -EINVAL;
> +
> + sa_index = ((void *)sa_entry - pf->ipsec.outb_sa->base) / sa_size;
> + if (sa_index >= CN10K_IPSEC_OUTB_MAX_SA)
> + return -EINVAL;
> +
> + return sa_index;
> +}
> +
> +static dma_addr_t cn10k_outb_get_sa_iova(struct otx2_nic *pf,
> + struct cn10k_tx_sa_s *sa_entry)
> +{
> + u32 sa_index = cn10k_outb_get_sa_index(pf, sa_entry);
> +
> + if (sa_index < 0)
> + return 0;
Should the type of sa_index be int?
That would match the return type of cn10k_outb_get_sa_index.
Otherwise, testing for < 0 will always be false.
Likewise in cn10k_outb_free_sa and cn10k_ipsec_del_state.
Flagged by Smatch.
> + return pf->ipsec.outb_sa->iova + sa_index * pf->ipsec.sa_size;
> +}
...
> +static int cn10k_outb_write_sa(struct otx2_nic *pf, struct cn10k_tx_sa_s *sa_cptr)
> +{
> + dma_addr_t res_iova, dptr_iova, sa_iova;
> + struct cn10k_tx_sa_s *sa_dptr;
> + struct cpt_inst_s inst;
> + struct cpt_res_s *res;
> + u32 sa_size, off;
> + u64 reg_val;
> + int ret;
> +
> + sa_iova = cn10k_outb_get_sa_iova(pf, sa_cptr);
> + if (!sa_iova)
> + return -EINVAL;
> +
> + res = dma_alloc_coherent(pf->dev, sizeof(struct cpt_res_s),
> + &res_iova, GFP_ATOMIC);
> + if (!res)
> + return -ENOMEM;
> +
> + sa_size = sizeof(struct cn10k_tx_sa_s);
> + sa_dptr = dma_alloc_coherent(pf->dev, sa_size, &dptr_iova, GFP_ATOMIC);
> + if (!sa_dptr) {
> + dma_free_coherent(pf->dev, sizeof(struct cpt_res_s), res,
> + res_iova);
> + return -ENOMEM;
> + }
> +
> + for (off = 0; off < (sa_size / 8); off++)
> + *((u64 *)sa_dptr + off) = cpu_to_be64(*((u64 *)sa_cptr + off));
Given the layout of struct cn10k_tx_sa_s, it's not clear
to me how it makes sense for it to be used to store big endian quadwords.
Which is a something that probably ought to be addressed.
But if not, Sparse complains about the endienness of the types used
above. I think it wants:
*((__be64 *)sa_dptr + off)
> +
> + memset(&inst, 0, sizeof(struct cpt_inst_s));
> +
> + res->compcode = CN10K_CPT_COMP_E_NOTDONE;
> + inst.res_addr = res_iova;
> + inst.dptr = (u64)dptr_iova;
> + inst.param2 = sa_size >> 3;
> + inst.dlen = sa_size;
> + inst.opcode_major = CN10K_IPSEC_MAJOR_OP_WRITE_SA;
> + inst.opcode_minor = CN10K_IPSEC_MINOR_OP_WRITE_SA;
> + inst.cptr = sa_iova;
> + inst.ctx_val = 1;
> + inst.egrp = CN10K_DEF_CPT_IPSEC_EGRP;
> +
> + cn10k_cpt_inst_flush(pf, &inst, sizeof(struct cpt_inst_s));
> + dma_wmb();
> + ret = cn10k_wait_for_cpt_respose(pf, res);
> + if (ret)
> + goto out;
> +
> + /* Trigger CTX flush to write dirty data back to DRAM */
> + reg_val = FIELD_PREP(CPT_LF_CTX_FLUSH, sa_iova >> 7);
> + otx2_write64(pf, CN10K_CPT_LF_CTX_FLUSH, reg_val);
> +
> +out:
> + dma_free_coherent(pf->dev, sa_size, sa_dptr, dptr_iova);
> + dma_free_coherent(pf->dev, sizeof(struct cpt_res_s), res, res_iova);
> + return ret;
> +}
...
> +static void cn10k_outb_prepare_sa(struct xfrm_state *x,
> + struct cn10k_tx_sa_s *sa_entry)
> +{
> + int key_len = (x->aead->alg_key_len + 7) / 8;
> + struct net_device *netdev = x->xso.dev;
> + u8 *key = x->aead->alg_key;
> + struct otx2_nic *pf;
> + u32 *tmp_salt;
> + u64 *tmp_key;
> + int idx;
> +
> + memset(sa_entry, 0, sizeof(struct cn10k_tx_sa_s));
> +
> + /* context size, 128 Byte aligned up */
> + pf = netdev_priv(netdev);
> + sa_entry->ctx_size = (pf->ipsec.sa_size / OTX2_ALIGN) & 0xF;
> + sa_entry->hw_ctx_off = cn10k_ipsec_get_hw_ctx_offset();
> + sa_entry->ctx_push_size = cn10k_ipsec_get_ctx_push_size();
> +
> + /* Ucode to skip two words of CPT_CTX_HW_S */
> + sa_entry->ctx_hdr_size = 1;
> +
> + /* Allow Atomic operation (AOP) */
> + sa_entry->aop_valid = 1;
> +
> + /* Outbound, ESP TRANSPORT/TUNNEL Mode, AES-GCM with AES key length
> + * 128bit.
> + */
> + sa_entry->sa_dir = CN10K_IPSEC_SA_DIR_OUTB;
> + sa_entry->ipsec_protocol = CN10K_IPSEC_SA_IPSEC_PROTO_ESP;
> + sa_entry->enc_type = CN10K_IPSEC_SA_ENCAP_TYPE_AES_GCM;
> + if (x->props.mode == XFRM_MODE_TUNNEL)
> + sa_entry->ipsec_mode = CN10K_IPSEC_SA_IPSEC_MODE_TUNNEL;
> + else
> + sa_entry->ipsec_mode = CN10K_IPSEC_SA_IPSEC_MODE_TRANSPORT;
> +
> + sa_entry->spi = cpu_to_be32(x->id.spi);
The type of spi is a 32-bit bitfield of a 64-bit unsigned host endien integer.
1. I suspect it would make more sense to declare that field as a 32bit integer.
2. It is being assigned a big endian value. That doesn't seem right.
The second issue was flagged by Sparse.
> +
> + /* Last 4 bytes are salt */
> + key_len -= 4;
> + sa_entry->aes_key_len = cn10k_ipsec_get_aes_key_len(key_len);
> + memcpy(sa_entry->cipher_key, key, key_len);
> + tmp_key = (u64 *)sa_entry->cipher_key;
> +
> + for (idx = 0; idx < key_len / 8; idx++)
> + tmp_key[idx] = be64_to_cpu(tmp_key[idx]);
More endian problems flagged by Sparse on this line.
An integer variable should typically be used to store
a big endian value, a little endian value, or a host endian value.
Not more than one of these.
This is because tooling such as Sparse can then be used to verify
the correctness of the endian used.
> +
> + memcpy(&sa_entry->iv_gcm_salt, key + key_len, 4);
> + tmp_salt = (u32 *)&sa_entry->iv_gcm_salt;
> + *tmp_salt = be32_to_cpu(*tmp_salt);
Likewise here.
> +
> + /* Write SA context data to memory before enabling */
> + wmb();
> +
> + /* Enable SA */
> + sa_entry->sa_valid = 1;
> +}
...
> +static int cn10k_ipsec_add_state(struct xfrm_state *x,
> + struct netlink_ext_ack *extack)
> +{
> + struct net_device *netdev = x->xso.dev;
> + struct cn10k_tx_sa_s *sa_entry;
> + struct cpt_ctx_info_s *sa_info;
> + struct otx2_nic *pf;
> + int err;
> +
> + err = cn10k_ipsec_validate_state(x);
> + if (err)
> + return err;
> +
> + if (x->xso.dir == XFRM_DEV_OFFLOAD_IN) {
> + netdev_err(netdev, "xfrm inbound offload not supported\n");
> + err = -ENODEV;
This path results in pf being dereferenced while uninitialised
towards the bottom of this function.
Flagged by Smatch, and Clang-18 W=1 build
> + } else {
> + pf = netdev_priv(netdev);
> + if (!mutex_trylock(&pf->ipsec.lock)) {
> + netdev_err(netdev, "IPSEC device is busy\n");
> + return -EBUSY;
> + }
> +
> + if (!(pf->flags & OTX2_FLAG_INLINE_IPSEC_ENABLED)) {
> + netdev_err(netdev, "IPSEC not enabled/supported on device\n");
> + err = -ENODEV;
> + goto unlock;
> + }
> +
> + sa_entry = cn10k_outb_alloc_sa(pf);
> + if (!sa_entry) {
> + netdev_err(netdev, "SA maximum limit %x reached\n",
> + CN10K_IPSEC_OUTB_MAX_SA);
> + err = -EBUSY;
> + goto unlock;
> + }
> +
> + cn10k_outb_prepare_sa(x, sa_entry);
> +
> + err = cn10k_outb_write_sa(pf, sa_entry);
> + if (err) {
> + netdev_err(netdev, "Error writing outbound SA\n");
> + cn10k_outb_free_sa(pf, sa_entry);
> + goto unlock;
> + }
> +
> + sa_info = kmalloc(sizeof(*sa_info), GFP_KERNEL);
> + sa_info->sa_entry = sa_entry;
> + sa_info->sa_iova = cn10k_outb_get_sa_iova(pf, sa_entry);
> + x->xso.offload_handle = (unsigned long)sa_info;
> + }
> +
> +unlock:
> + mutex_unlock(&pf->ipsec.lock);
> + return err;
> +}
...
> +static const struct xfrmdev_ops cn10k_ipsec_xfrmdev_ops = {
> + .xdo_dev_state_add = cn10k_ipsec_add_state,
> + .xdo_dev_state_delete = cn10k_ipsec_del_state,
> +};
> +
cn10k_ipsec_xfrmdev_ops is unused.
Perhaps it, along with it's callbacks,
should be added by the function that uses it?
Flagged by W=1 builds.
> int cn10k_ipsec_ethtool_init(struct net_device *netdev, bool enable)
> {
> struct otx2_nic *pf = netdev_priv(netdev);
...
> diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/cn10k_ipsec.h b/drivers/net/ethernet/marvell/octeontx2/nic/cn10k_ipsec.h
...
> +struct cn10k_tx_sa_s {
> + u64 esn_en : 1; /* W0 */
> + u64 rsvd_w0_1_8 : 8;
> + u64 hw_ctx_off : 7;
> + u64 ctx_id : 16;
> + u64 rsvd_w0_32_47 : 16;
> + u64 ctx_push_size : 7;
> + u64 rsvd_w0_55 : 1;
> + u64 ctx_hdr_size : 2;
> + u64 aop_valid : 1;
> + u64 rsvd_w0_59 : 1;
> + u64 ctx_size : 4;
> + u64 w1; /* W1 */
> + u64 sa_valid : 1; /* W2 */
> + u64 sa_dir : 1;
> + u64 rsvd_w2_2_3 : 2;
> + u64 ipsec_mode : 1;
> + u64 ipsec_protocol : 1;
> + u64 aes_key_len : 2;
> + u64 enc_type : 3;
> + u64 rsvd_w2_11_31 : 21;
> + u64 spi : 32;
> + u64 w3; /* W3 */
> + u8 cipher_key[32]; /* W4 - W7 */
> + u32 rsvd_w8_0_31; /* W8 : IV */
> + u32 iv_gcm_salt;
> + u64 rsvd_w9_w30[22]; /* W9 - W30 */
> + u64 hw_ctx[6]; /* W31 - W36 */
> +};
...
next prev parent reply other threads:[~2024-05-13 16:51 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-05-13 10:54 [net-next,v2 0/8] cn10k-ipsec: Add outbound inline ipsec support Bharat Bhushan
2024-05-13 10:54 ` [net-next,v2 1/8] octeontx2-pf: map skb data as device writeable Bharat Bhushan
2024-05-13 10:54 ` [net-next,v2 2/8] octeontx2-pf: Move skb fragment map/unmap to common code Bharat Bhushan
2024-05-13 10:54 ` [net-next,v2 3/8] octeontx2-af: Disable backpressure between CPT and NIX Bharat Bhushan
2024-05-13 16:14 ` Simon Horman
2024-05-14 6:39 ` [EXTERNAL] " Bharat Bhushan
2024-05-14 10:41 ` Simon Horman
2024-05-14 11:26 ` Bharat Bhushan
2024-05-14 11:45 ` Simon Horman
2024-05-13 10:54 ` [net-next,v2 4/8] cn10k-ipsec: Initialize crypto hardware for outb inline ipsec Bharat Bhushan
2024-05-13 10:54 ` [net-next,v2 5/8] cn10k-ipsec: Add SA add/delete support " Bharat Bhushan
2024-05-13 16:51 ` Simon Horman [this message]
2024-05-14 6:52 ` [EXTERNAL] " Bharat Bhushan
2024-05-14 10:46 ` Simon Horman
2024-05-14 8:15 ` kernel test robot
2024-05-13 10:54 ` [net-next,v2 6/8] cn10k-ipsec: Process inline ipsec transmit offload Bharat Bhushan
2024-05-13 10:54 ` [net-next,v2 7/8] cn10k-ipsec: Allow inline ipsec offload for skb with SA Bharat Bhushan
2024-05-13 10:54 ` [net-next,v2 8/8] cn10k-ipsec: Enable outbound inline ipsec offload Bharat Bhushan
2024-05-13 12:22 ` [net-next,v2 0/8] cn10k-ipsec: Add outbound inline ipsec support Kalesh Anakkur Purayil
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20240513165133.GS2787@kernel.org \
--to=horms@kernel.org \
--cc=bbhushan2@marvell.com \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=gakula@marvell.com \
--cc=hkelam@marvell.com \
--cc=jerinj@marvell.com \
--cc=kuba@kernel.org \
--cc=lcherian@marvell.com \
--cc=linux-kernel@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=richardcochran@gmail.com \
--cc=sbhatta@marvell.com \
--cc=sgoutham@marvell.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.