Commit 436396f2 authored by Huanhuan Wang's avatar Huanhuan Wang Committed by Jakub Kicinski

nfp: support IPsec offloading for NFP3800

Add IPsec offloading support for NFP3800. Include data
plane and control plane.

Data plane: add IPsec packet process flow in NFP3800
datapath (NFDk).

Control plane: add an algorithm support distinction flow
in xfrm hook function xdo_dev_state_add(), as NFP3800 has
a different set of IPsec algorithm support.

This matches existing support for the NFP6000/NFP4000 and
their NFD3 datapath.

In addition, fixup the md_bytes calculation for NFD3 datapath
to make sure the two datapahts are keept in sync.
Signed-off-by: default avatarHuanhuan Wang <huanhuan.wang@corigine.com>
Reviewed-by: default avatarNiklas Söderlund <niklas.soderlund@corigine.com>
Signed-off-by: default avatarSimon Horman <simon.horman@corigine.com>
Reviewed-by: default avatarLeon Romanovsky <leonro@nvidia.com>
Link: https://lore.kernel.org/r/20230208091000.4139974-1-simon.horman@corigine.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 2894d353
...@@ -80,7 +80,7 @@ nfp-objs += \ ...@@ -80,7 +80,7 @@ nfp-objs += \
abm/main.o abm/main.o
endif endif
nfp-$(CONFIG_NFP_NET_IPSEC) += crypto/ipsec.o nfd3/ipsec.o nfp-$(CONFIG_NFP_NET_IPSEC) += crypto/ipsec.o nfd3/ipsec.o nfdk/ipsec.o
nfp-$(CONFIG_NFP_DEBUG) += nfp_net_debugfs.o nfp-$(CONFIG_NFP_DEBUG) += nfp_net_debugfs.o
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <linux/ktime.h> #include <linux/ktime.h>
#include <net/xfrm.h> #include <net/xfrm.h>
#include "../nfpcore/nfp_dev.h"
#include "../nfp_net_ctrl.h" #include "../nfp_net_ctrl.h"
#include "../nfp_net.h" #include "../nfp_net.h"
#include "crypto.h" #include "crypto.h"
...@@ -330,6 +331,10 @@ static int nfp_net_xfrm_add_state(struct xfrm_state *x, ...@@ -330,6 +331,10 @@ static int nfp_net_xfrm_add_state(struct xfrm_state *x,
trunc_len = -1; trunc_len = -1;
break; break;
case SADB_AALG_MD5HMAC: case SADB_AALG_MD5HMAC:
if (nn->pdev->device == PCI_DEVICE_ID_NFP3800) {
NL_SET_ERR_MSG_MOD(extack, "Unsupported authentication algorithm");
return -EINVAL;
}
set_md5hmac(cfg, &trunc_len); set_md5hmac(cfg, &trunc_len);
break; break;
case SADB_AALG_SHA1HMAC: case SADB_AALG_SHA1HMAC:
...@@ -373,6 +378,10 @@ static int nfp_net_xfrm_add_state(struct xfrm_state *x, ...@@ -373,6 +378,10 @@ static int nfp_net_xfrm_add_state(struct xfrm_state *x,
cfg->ctrl_word.cipher = NFP_IPSEC_CIPHER_NULL; cfg->ctrl_word.cipher = NFP_IPSEC_CIPHER_NULL;
break; break;
case SADB_EALG_3DESCBC: case SADB_EALG_3DESCBC:
if (nn->pdev->device == PCI_DEVICE_ID_NFP3800) {
NL_SET_ERR_MSG_MOD(extack, "Unsupported encryption algorithm for offload");
return -EINVAL;
}
cfg->ctrl_word.cimode = NFP_IPSEC_CIMODE_CBC; cfg->ctrl_word.cimode = NFP_IPSEC_CIMODE_CBC;
cfg->ctrl_word.cipher = NFP_IPSEC_CIPHER_3DES; cfg->ctrl_word.cipher = NFP_IPSEC_CIPHER_3DES;
break; break;
......
...@@ -192,10 +192,10 @@ static int nfp_nfd3_prep_tx_meta(struct nfp_net_dp *dp, struct sk_buff *skb, ...@@ -192,10 +192,10 @@ static int nfp_nfd3_prep_tx_meta(struct nfp_net_dp *dp, struct sk_buff *skb,
return 0; return 0;
md_bytes = sizeof(meta_id) + md_bytes = sizeof(meta_id) +
!!md_dst * NFP_NET_META_PORTID_SIZE + (!!md_dst ? NFP_NET_META_PORTID_SIZE : 0) +
!!tls_handle * NFP_NET_META_CONN_HANDLE_SIZE + (!!tls_handle ? NFP_NET_META_CONN_HANDLE_SIZE : 0) +
vlan_insert * NFP_NET_META_VLAN_SIZE + (vlan_insert ? NFP_NET_META_VLAN_SIZE : 0) +
*ipsec * NFP_NET_META_IPSEC_FIELD_SIZE; /* IPsec has 12 bytes of metadata */ (*ipsec ? NFP_NET_META_IPSEC_FIELD_SIZE : 0);
if (unlikely(skb_cow_head(skb, md_bytes))) if (unlikely(skb_cow_head(skb, md_bytes)))
return -ENOMEM; return -ENOMEM;
...@@ -226,9 +226,6 @@ static int nfp_nfd3_prep_tx_meta(struct nfp_net_dp *dp, struct sk_buff *skb, ...@@ -226,9 +226,6 @@ static int nfp_nfd3_prep_tx_meta(struct nfp_net_dp *dp, struct sk_buff *skb,
meta_id |= NFP_NET_META_VLAN; meta_id |= NFP_NET_META_VLAN;
} }
if (*ipsec) { if (*ipsec) {
/* IPsec has three consecutive 4-bit IPsec metadata types,
* so in total IPsec has three 4 bytes of metadata.
*/
data -= NFP_NET_META_IPSEC_SIZE; data -= NFP_NET_META_IPSEC_SIZE;
put_unaligned_be32(offload_info.seq_hi, data); put_unaligned_be32(offload_info.seq_hi, data);
data -= NFP_NET_META_IPSEC_SIZE; data -= NFP_NET_META_IPSEC_SIZE;
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include <linux/overflow.h> #include <linux/overflow.h>
#include <linux/sizes.h> #include <linux/sizes.h>
#include <linux/bitfield.h> #include <linux/bitfield.h>
#include <net/xfrm.h>
#include "../nfp_app.h" #include "../nfp_app.h"
#include "../nfp_net.h" #include "../nfp_net.h"
...@@ -172,25 +173,32 @@ nfp_nfdk_tx_maybe_close_block(struct nfp_net_tx_ring *tx_ring, ...@@ -172,25 +173,32 @@ nfp_nfdk_tx_maybe_close_block(struct nfp_net_tx_ring *tx_ring,
static int static int
nfp_nfdk_prep_tx_meta(struct nfp_net_dp *dp, struct nfp_app *app, nfp_nfdk_prep_tx_meta(struct nfp_net_dp *dp, struct nfp_app *app,
struct sk_buff *skb) struct sk_buff *skb, bool *ipsec)
{ {
struct metadata_dst *md_dst = skb_metadata_dst(skb); struct metadata_dst *md_dst = skb_metadata_dst(skb);
struct nfp_ipsec_offload offload_info;
unsigned char *data; unsigned char *data;
bool vlan_insert; bool vlan_insert;
u32 meta_id = 0; u32 meta_id = 0;
int md_bytes; int md_bytes;
#ifdef CONFIG_NFP_NET_IPSEC
if (xfrm_offload(skb))
*ipsec = nfp_net_ipsec_tx_prep(dp, skb, &offload_info);
#endif
if (unlikely(md_dst && md_dst->type != METADATA_HW_PORT_MUX)) if (unlikely(md_dst && md_dst->type != METADATA_HW_PORT_MUX))
md_dst = NULL; md_dst = NULL;
vlan_insert = skb_vlan_tag_present(skb) && (dp->ctrl & NFP_NET_CFG_CTRL_TXVLAN_V2); vlan_insert = skb_vlan_tag_present(skb) && (dp->ctrl & NFP_NET_CFG_CTRL_TXVLAN_V2);
if (!(md_dst || vlan_insert)) if (!(md_dst || vlan_insert || *ipsec))
return 0; return 0;
md_bytes = sizeof(meta_id) + md_bytes = sizeof(meta_id) +
!!md_dst * NFP_NET_META_PORTID_SIZE + (!!md_dst ? NFP_NET_META_PORTID_SIZE : 0) +
vlan_insert * NFP_NET_META_VLAN_SIZE; (vlan_insert ? NFP_NET_META_VLAN_SIZE : 0) +
(*ipsec ? NFP_NET_META_IPSEC_FIELD_SIZE : 0);
if (unlikely(skb_cow_head(skb, md_bytes))) if (unlikely(skb_cow_head(skb, md_bytes)))
return -ENOMEM; return -ENOMEM;
...@@ -212,6 +220,17 @@ nfp_nfdk_prep_tx_meta(struct nfp_net_dp *dp, struct nfp_app *app, ...@@ -212,6 +220,17 @@ nfp_nfdk_prep_tx_meta(struct nfp_net_dp *dp, struct nfp_app *app,
meta_id |= NFP_NET_META_VLAN; meta_id |= NFP_NET_META_VLAN;
} }
if (*ipsec) {
data -= NFP_NET_META_IPSEC_SIZE;
put_unaligned_be32(offload_info.seq_hi, data);
data -= NFP_NET_META_IPSEC_SIZE;
put_unaligned_be32(offload_info.seq_low, data);
data -= NFP_NET_META_IPSEC_SIZE;
put_unaligned_be32(offload_info.handle - 1, data);
meta_id <<= NFP_NET_META_IPSEC_FIELD_SIZE;
meta_id |= NFP_NET_META_IPSEC << 8 | NFP_NET_META_IPSEC << 4 | NFP_NET_META_IPSEC;
}
meta_id = FIELD_PREP(NFDK_META_LEN, md_bytes) | meta_id = FIELD_PREP(NFDK_META_LEN, md_bytes) |
FIELD_PREP(NFDK_META_FIELDS, meta_id); FIELD_PREP(NFDK_META_FIELDS, meta_id);
...@@ -243,6 +262,7 @@ netdev_tx_t nfp_nfdk_tx(struct sk_buff *skb, struct net_device *netdev) ...@@ -243,6 +262,7 @@ netdev_tx_t nfp_nfdk_tx(struct sk_buff *skb, struct net_device *netdev)
struct nfp_net_dp *dp; struct nfp_net_dp *dp;
int nr_frags, wr_idx; int nr_frags, wr_idx;
dma_addr_t dma_addr; dma_addr_t dma_addr;
bool ipsec = false;
u64 metadata; u64 metadata;
dp = &nn->dp; dp = &nn->dp;
...@@ -263,7 +283,7 @@ netdev_tx_t nfp_nfdk_tx(struct sk_buff *skb, struct net_device *netdev) ...@@ -263,7 +283,7 @@ netdev_tx_t nfp_nfdk_tx(struct sk_buff *skb, struct net_device *netdev)
return NETDEV_TX_BUSY; return NETDEV_TX_BUSY;
} }
metadata = nfp_nfdk_prep_tx_meta(dp, nn->app, skb); metadata = nfp_nfdk_prep_tx_meta(dp, nn->app, skb, &ipsec);
if (unlikely((int)metadata < 0)) if (unlikely((int)metadata < 0))
goto err_flush; goto err_flush;
...@@ -361,6 +381,9 @@ netdev_tx_t nfp_nfdk_tx(struct sk_buff *skb, struct net_device *netdev) ...@@ -361,6 +381,9 @@ netdev_tx_t nfp_nfdk_tx(struct sk_buff *skb, struct net_device *netdev)
(txd - 1)->dma_len_type = cpu_to_le16(dlen_type | NFDK_DESC_TX_EOP); (txd - 1)->dma_len_type = cpu_to_le16(dlen_type | NFDK_DESC_TX_EOP);
if (ipsec)
metadata = nfp_nfdk_ipsec_tx(metadata, skb);
if (!skb_is_gso(skb)) { if (!skb_is_gso(skb)) {
real_len = skb->len; real_len = skb->len;
/* Metadata desc */ /* Metadata desc */
...@@ -760,6 +783,15 @@ nfp_nfdk_parse_meta(struct net_device *netdev, struct nfp_meta_parsed *meta, ...@@ -760,6 +783,15 @@ nfp_nfdk_parse_meta(struct net_device *netdev, struct nfp_meta_parsed *meta,
return false; return false;
data += sizeof(struct nfp_net_tls_resync_req); data += sizeof(struct nfp_net_tls_resync_req);
break; break;
#ifdef CONFIG_NFP_NET_IPSEC
case NFP_NET_META_IPSEC:
/* Note: IPsec packet could have zero saidx, so need add 1
* to indicate packet is IPsec packet within driver.
*/
meta->ipsec_saidx = get_unaligned_be32(data) + 1;
data += 4;
break;
#endif
default: default:
return true; return true;
} }
...@@ -1186,6 +1218,13 @@ static int nfp_nfdk_rx(struct nfp_net_rx_ring *rx_ring, int budget) ...@@ -1186,6 +1218,13 @@ static int nfp_nfdk_rx(struct nfp_net_rx_ring *rx_ring, int budget)
continue; continue;
} }
#ifdef CONFIG_NFP_NET_IPSEC
if (meta.ipsec_saidx != 0 && unlikely(nfp_net_ipsec_rx(&meta, skb))) {
nfp_nfdk_rx_drop(dp, r_vec, rx_ring, NULL, skb);
continue;
}
#endif
if (meta_len_xdp) if (meta_len_xdp)
skb_metadata_set(skb, meta_len_xdp); skb_metadata_set(skb, meta_len_xdp);
......
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
/* Copyright (C) 2023 Corigine, Inc */
#include <net/xfrm.h>
#include "../nfp_net.h"
#include "nfdk.h"
u64 nfp_nfdk_ipsec_tx(u64 flags, struct sk_buff *skb)
{
struct xfrm_state *x = xfrm_input_state(skb);
if (x->xso.dev && (x->xso.dev->features & NETIF_F_HW_ESP_TX_CSUM))
flags |= NFDK_DESC_TX_L3_CSUM | NFDK_DESC_TX_L4_CSUM;
return flags;
}
...@@ -125,4 +125,12 @@ nfp_nfdk_ctrl_tx_one(struct nfp_net *nn, struct nfp_net_r_vector *r_vec, ...@@ -125,4 +125,12 @@ nfp_nfdk_ctrl_tx_one(struct nfp_net *nn, struct nfp_net_r_vector *r_vec,
void nfp_nfdk_ctrl_poll(struct tasklet_struct *t); void nfp_nfdk_ctrl_poll(struct tasklet_struct *t);
void nfp_nfdk_rx_ring_fill_freelist(struct nfp_net_dp *dp, void nfp_nfdk_rx_ring_fill_freelist(struct nfp_net_dp *dp,
struct nfp_net_rx_ring *rx_ring); struct nfp_net_rx_ring *rx_ring);
#ifndef CONFIG_NFP_NET_IPSEC
static inline u64 nfp_nfdk_ipsec_tx(u64 flags, struct sk_buff *skb)
{
return flags;
}
#else
u64 nfp_nfdk_ipsec_tx(u64 flags, struct sk_buff *skb);
#endif
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment