Skip to content

Commit 57f273a

Browse files
wanghuanhuan12davem330
authored andcommitted
nfp: add framework to support ipsec offloading
A new metadata type and config structure are introduced to interact with firmware to support ipsec offloading. This feature relies on specific firmware that supports ipsec encrypt/decrypt by advertising related capability bit. The xfrm callbacks which interact with upper layer are implemented in the following patch. Based on initial work of Norm Bagley <norman.bagley@netronome.com>. Signed-off-by: Huanhuan Wang <huanhuan.wang@corigine.com> Reviewed-by: Louis Peens <louis.peens@corigine.com> Signed-off-by: Simon Horman <simon.horman@corigine.com> Reviewed-by: Leon Romanovsky <leonro@nvidia.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 484963c commit 57f273a

File tree

10 files changed

+233
-10
lines changed

10 files changed

+233
-10
lines changed

drivers/net/ethernet/netronome/Kconfig

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,17 @@ config NFP_APP_ABM_NIC
5454
functionality.
5555
Code will be built into the nfp.ko driver.
5656

57+
config NFP_NET_IPSEC
58+
bool "NFP IPsec crypto offload support"
59+
depends on NFP
60+
depends on XFRM_OFFLOAD
61+
default y
62+
help
63+
Enable driver support IPsec crypto offload on NFP NIC.
64+
Say Y, if you are planning to make use of IPsec crypto
65+
offload. NOTE that IPsec crypto offload on NFP NIC
66+
requires specific FW to work.
67+
5768
config NFP_DEBUG
5869
bool "Debug support for Netronome(R) NFP4000/NFP6000 NIC drivers"
5970
depends on NFP

drivers/net/ethernet/netronome/nfp/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,4 +80,6 @@ nfp-objs += \
8080
abm/main.o
8181
endif
8282

83+
nfp-$(CONFIG_NFP_NET_IPSEC) += crypto/ipsec.o nfd3/ipsec.o
84+
8385
nfp-$(CONFIG_NFP_DEBUG) += nfp_net_debugfs.o

drivers/net/ethernet/netronome/nfp/crypto/crypto.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,27 @@ nfp_net_tls_rx_resync_req(struct net_device *netdev,
3939
}
4040
#endif
4141

42+
/* IPsec related structures and functions */
43+
struct nfp_ipsec_offload {
44+
u32 seq_hi;
45+
u32 seq_low;
46+
u32 handle;
47+
};
48+
49+
#ifndef CONFIG_NFP_NET_IPSEC
50+
static inline void nfp_net_ipsec_init(struct nfp_net *nn)
51+
{
52+
}
53+
54+
static inline void nfp_net_ipsec_clean(struct nfp_net *nn)
55+
{
56+
}
57+
#else
58+
void nfp_net_ipsec_init(struct nfp_net *nn);
59+
void nfp_net_ipsec_clean(struct nfp_net *nn);
60+
bool nfp_net_ipsec_tx_prep(struct nfp_net_dp *dp, struct sk_buff *skb,
61+
struct nfp_ipsec_offload *offload_info);
62+
int nfp_net_ipsec_rx(struct nfp_meta_parsed *meta, struct sk_buff *skb);
63+
#endif
64+
4265
#endif
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2+
/* Copyright (C) 2018 Netronome Systems, Inc */
3+
/* Copyright (C) 2021 Corigine, Inc */
4+
5+
#include <linux/module.h>
6+
#include <linux/kernel.h>
7+
#include <linux/init.h>
8+
#include <linux/netdevice.h>
9+
#include <asm/unaligned.h>
10+
#include <linux/ktime.h>
11+
#include <net/xfrm.h>
12+
13+
#include "../nfp_net_ctrl.h"
14+
#include "../nfp_net.h"
15+
#include "crypto.h"
16+
17+
#define NFP_NET_IPSEC_MAX_SA_CNT (16 * 1024) /* Firmware support a maximum of 16K SA offload */
18+
19+
static int nfp_net_xfrm_add_state(struct xfrm_state *x)
20+
{
21+
return -EOPNOTSUPP;
22+
}
23+
24+
static void nfp_net_xfrm_del_state(struct xfrm_state *x)
25+
{
26+
}
27+
28+
static bool nfp_net_ipsec_offload_ok(struct sk_buff *skb, struct xfrm_state *x)
29+
{
30+
return false;
31+
}
32+
33+
static const struct xfrmdev_ops nfp_net_ipsec_xfrmdev_ops = {
34+
.xdo_dev_state_add = nfp_net_xfrm_add_state,
35+
.xdo_dev_state_delete = nfp_net_xfrm_del_state,
36+
.xdo_dev_offload_ok = nfp_net_ipsec_offload_ok,
37+
};
38+
39+
void nfp_net_ipsec_init(struct nfp_net *nn)
40+
{
41+
if (!(nn->cap_w1 & NFP_NET_CFG_CTRL_IPSEC))
42+
return;
43+
44+
xa_init_flags(&nn->xa_ipsec, XA_FLAGS_ALLOC);
45+
nn->dp.netdev->xfrmdev_ops = &nfp_net_ipsec_xfrmdev_ops;
46+
}
47+
48+
void nfp_net_ipsec_clean(struct nfp_net *nn)
49+
{
50+
if (!(nn->cap_w1 & NFP_NET_CFG_CTRL_IPSEC))
51+
return;
52+
53+
WARN_ON(!xa_empty(&nn->xa_ipsec));
54+
xa_destroy(&nn->xa_ipsec);
55+
}
56+
57+
bool nfp_net_ipsec_tx_prep(struct nfp_net_dp *dp, struct sk_buff *skb,
58+
struct nfp_ipsec_offload *offload_info)
59+
{
60+
struct xfrm_offload *xo = xfrm_offload(skb);
61+
struct xfrm_state *x;
62+
63+
x = xfrm_input_state(skb);
64+
if (!x)
65+
return false;
66+
67+
offload_info->seq_hi = xo->seq.hi;
68+
offload_info->seq_low = xo->seq.low;
69+
offload_info->handle = x->xso.offload_handle;
70+
71+
return true;
72+
}
73+
74+
int nfp_net_ipsec_rx(struct nfp_meta_parsed *meta, struct sk_buff *skb)
75+
{
76+
struct net_device *netdev = skb->dev;
77+
struct xfrm_offload *xo;
78+
struct xfrm_state *x;
79+
struct sec_path *sp;
80+
struct nfp_net *nn;
81+
u32 saidx;
82+
83+
nn = netdev_priv(netdev);
84+
85+
saidx = meta->ipsec_saidx - 1;
86+
if (saidx >= NFP_NET_IPSEC_MAX_SA_CNT)
87+
return -EINVAL;
88+
89+
sp = secpath_set(skb);
90+
if (unlikely(!sp))
91+
return -ENOMEM;
92+
93+
xa_lock(&nn->xa_ipsec);
94+
x = xa_load(&nn->xa_ipsec, saidx);
95+
xa_unlock(&nn->xa_ipsec);
96+
if (!x)
97+
return -EINVAL;
98+
99+
xfrm_state_hold(x);
100+
sp->xvec[sp->len++] = x;
101+
sp->olen++;
102+
xo = xfrm_offload(skb);
103+
xo->flags = CRYPTO_DONE;
104+
xo->status = CRYPTO_SUCCESS;
105+
106+
return 0;
107+
}

drivers/net/ethernet/netronome/nfp/nfd3/dp.c

Lines changed: 48 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include <linux/bpf_trace.h>
55
#include <linux/netdevice.h>
66
#include <linux/bitfield.h>
7+
#include <net/xfrm.h>
78

89
#include "../nfp_app.h"
910
#include "../nfp_net.h"
@@ -167,28 +168,34 @@ nfp_nfd3_tx_csum(struct nfp_net_dp *dp, struct nfp_net_r_vector *r_vec,
167168
u64_stats_update_end(&r_vec->tx_sync);
168169
}
169170

170-
static int nfp_nfd3_prep_tx_meta(struct nfp_net_dp *dp, struct sk_buff *skb, u64 tls_handle)
171+
static int nfp_nfd3_prep_tx_meta(struct nfp_net_dp *dp, struct sk_buff *skb,
172+
u64 tls_handle, bool *ipsec)
171173
{
172174
struct metadata_dst *md_dst = skb_metadata_dst(skb);
175+
struct nfp_ipsec_offload offload_info;
173176
unsigned char *data;
174177
bool vlan_insert;
175178
u32 meta_id = 0;
176179
int md_bytes;
177180

178-
if (unlikely(md_dst || tls_handle)) {
179-
if (unlikely(md_dst && md_dst->type != METADATA_HW_PORT_MUX))
180-
md_dst = NULL;
181-
}
181+
#ifdef CONFIG_NFP_NET_IPSEC
182+
if (xfrm_offload(skb))
183+
*ipsec = nfp_net_ipsec_tx_prep(dp, skb, &offload_info);
184+
#endif
185+
186+
if (unlikely(md_dst && md_dst->type != METADATA_HW_PORT_MUX))
187+
md_dst = NULL;
182188

183189
vlan_insert = skb_vlan_tag_present(skb) && (dp->ctrl & NFP_NET_CFG_CTRL_TXVLAN_V2);
184190

185-
if (!(md_dst || tls_handle || vlan_insert))
191+
if (!(md_dst || tls_handle || vlan_insert || *ipsec))
186192
return 0;
187193

188194
md_bytes = sizeof(meta_id) +
189195
!!md_dst * NFP_NET_META_PORTID_SIZE +
190196
!!tls_handle * NFP_NET_META_CONN_HANDLE_SIZE +
191-
vlan_insert * NFP_NET_META_VLAN_SIZE;
197+
vlan_insert * NFP_NET_META_VLAN_SIZE +
198+
*ipsec * NFP_NET_META_IPSEC_FIELD_SIZE; /* IPsec has 12 bytes of metadata */
192199

193200
if (unlikely(skb_cow_head(skb, md_bytes)))
194201
return -ENOMEM;
@@ -218,6 +225,19 @@ static int nfp_nfd3_prep_tx_meta(struct nfp_net_dp *dp, struct sk_buff *skb, u64
218225
meta_id <<= NFP_NET_META_FIELD_SIZE;
219226
meta_id |= NFP_NET_META_VLAN;
220227
}
228+
if (*ipsec) {
229+
/* IPsec has three consecutive 4-bit IPsec metadata types,
230+
* so in total IPsec has three 4 bytes of metadata.
231+
*/
232+
data -= NFP_NET_META_IPSEC_SIZE;
233+
put_unaligned_be32(offload_info.seq_hi, data);
234+
data -= NFP_NET_META_IPSEC_SIZE;
235+
put_unaligned_be32(offload_info.seq_low, data);
236+
data -= NFP_NET_META_IPSEC_SIZE;
237+
put_unaligned_be32(offload_info.handle - 1, data);
238+
meta_id <<= NFP_NET_META_IPSEC_FIELD_SIZE;
239+
meta_id |= NFP_NET_META_IPSEC << 8 | NFP_NET_META_IPSEC << 4 | NFP_NET_META_IPSEC;
240+
}
221241

222242
data -= sizeof(meta_id);
223243
put_unaligned_be32(meta_id, data);
@@ -246,6 +266,7 @@ netdev_tx_t nfp_nfd3_tx(struct sk_buff *skb, struct net_device *netdev)
246266
dma_addr_t dma_addr;
247267
unsigned int fsize;
248268
u64 tls_handle = 0;
269+
bool ipsec = false;
249270
u16 qidx;
250271

251272
dp = &nn->dp;
@@ -273,7 +294,7 @@ netdev_tx_t nfp_nfd3_tx(struct sk_buff *skb, struct net_device *netdev)
273294
return NETDEV_TX_OK;
274295
}
275296

276-
md_bytes = nfp_nfd3_prep_tx_meta(dp, skb, tls_handle);
297+
md_bytes = nfp_nfd3_prep_tx_meta(dp, skb, tls_handle, &ipsec);
277298
if (unlikely(md_bytes < 0))
278299
goto err_flush;
279300

@@ -312,6 +333,8 @@ netdev_tx_t nfp_nfd3_tx(struct sk_buff *skb, struct net_device *netdev)
312333
txd->vlan = cpu_to_le16(skb_vlan_tag_get(skb));
313334
}
314335

336+
if (ipsec)
337+
nfp_nfd3_ipsec_tx(txd, skb);
315338
/* Gather DMA */
316339
if (nr_frags > 0) {
317340
__le64 second_half;
@@ -764,6 +787,15 @@ nfp_nfd3_parse_meta(struct net_device *netdev, struct nfp_meta_parsed *meta,
764787
return false;
765788
data += sizeof(struct nfp_net_tls_resync_req);
766789
break;
790+
#ifdef CONFIG_NFP_NET_IPSEC
791+
case NFP_NET_META_IPSEC:
792+
/* Note: IPsec packet will have zero saidx, so need add 1
793+
* to indicate packet is IPsec packet within driver.
794+
*/
795+
meta->ipsec_saidx = get_unaligned_be32(data) + 1;
796+
data += 4;
797+
break;
798+
#endif
767799
default:
768800
return true;
769801
}
@@ -876,12 +908,11 @@ static int nfp_nfd3_rx(struct nfp_net_rx_ring *rx_ring, int budget)
876908
struct nfp_net_dp *dp = &r_vec->nfp_net->dp;
877909
struct nfp_net_tx_ring *tx_ring;
878910
struct bpf_prog *xdp_prog;
911+
int idx, pkts_polled = 0;
879912
bool xdp_tx_cmpl = false;
880913
unsigned int true_bufsz;
881914
struct sk_buff *skb;
882-
int pkts_polled = 0;
883915
struct xdp_buff xdp;
884-
int idx;
885916

886917
xdp_prog = READ_ONCE(dp->xdp_prog);
887918
true_bufsz = xdp_prog ? PAGE_SIZE : dp->fl_bufsz;
@@ -1081,6 +1112,13 @@ static int nfp_nfd3_rx(struct nfp_net_rx_ring *rx_ring, int budget)
10811112
continue;
10821113
}
10831114

1115+
#ifdef CONFIG_NFP_NET_IPSEC
1116+
if (meta.ipsec_saidx != 0 && unlikely(nfp_net_ipsec_rx(&meta, skb))) {
1117+
nfp_nfd3_rx_drop(dp, r_vec, rx_ring, NULL, skb);
1118+
continue;
1119+
}
1120+
#endif
1121+
10841122
if (meta_len_xdp)
10851123
skb_metadata_set(skb, meta_len_xdp);
10861124

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2+
/* Copyright (C) 2018 Netronome Systems, Inc */
3+
/* Copyright (C) 2021 Corigine, Inc */
4+
5+
#include <net/xfrm.h>
6+
7+
#include "../nfp_net.h"
8+
#include "nfd3.h"
9+
10+
void nfp_nfd3_ipsec_tx(struct nfp_nfd3_tx_desc *txd, struct sk_buff *skb)
11+
{
12+
struct xfrm_state *x = xfrm_input_state(skb);
13+
14+
if (x->xso.dev && (x->xso.dev->features & NETIF_F_HW_ESP_TX_CSUM)) {
15+
txd->flags |= NFD3_DESC_TX_CSUM | NFD3_DESC_TX_IP4_CSUM |
16+
NFD3_DESC_TX_TCP_CSUM | NFD3_DESC_TX_UDP_CSUM;
17+
}
18+
}

drivers/net/ethernet/netronome/nfp/nfd3/nfd3.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,4 +103,12 @@ void nfp_nfd3_rx_ring_fill_freelist(struct nfp_net_dp *dp,
103103
void nfp_nfd3_xsk_tx_free(struct nfp_nfd3_tx_buf *txbuf);
104104
int nfp_nfd3_xsk_poll(struct napi_struct *napi, int budget);
105105

106+
#ifndef CONFIG_NFP_NET_IPSEC
107+
static inline void nfp_nfd3_ipsec_tx(struct nfp_nfd3_tx_desc *txd, struct sk_buff *skb)
108+
{
109+
}
110+
#else
111+
void nfp_nfd3_ipsec_tx(struct nfp_nfd3_tx_desc *txd, struct sk_buff *skb);
112+
#endif
113+
106114
#endif

drivers/net/ethernet/netronome/nfp/nfp_net.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,10 @@ struct nfp_meta_parsed {
263263
u8 tpid;
264264
u16 tci;
265265
} vlan;
266+
267+
#ifdef CONFIG_NFP_NET_IPSEC
268+
u32 ipsec_saidx;
269+
#endif
266270
};
267271

268272
struct nfp_net_rx_hash {
@@ -584,6 +588,7 @@ struct nfp_net_dp {
584588
* @qcp_cfg: Pointer to QCP queue used for configuration notification
585589
* @tx_bar: Pointer to mapped TX queues
586590
* @rx_bar: Pointer to mapped FL/RX queues
591+
* @xa_ipsec: IPsec xarray SA data
587592
* @tlv_caps: Parsed TLV capabilities
588593
* @ktls_tx_conn_cnt: Number of offloaded kTLS TX connections
589594
* @ktls_rx_conn_cnt: Number of offloaded kTLS RX connections
@@ -672,6 +677,10 @@ struct nfp_net {
672677
u8 __iomem *tx_bar;
673678
u8 __iomem *rx_bar;
674679

680+
#ifdef CONFIG_NFP_NET_IPSEC
681+
struct xarray xa_ipsec;
682+
#endif
683+
675684
struct nfp_net_tlv_caps tlv_caps;
676685

677686
unsigned int ktls_tx_conn_cnt;

drivers/net/ethernet/netronome/nfp/nfp_net_common.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2564,6 +2564,8 @@ int nfp_net_init(struct nfp_net *nn)
25642564
err = nfp_net_tls_init(nn);
25652565
if (err)
25662566
goto err_clean_mbox;
2567+
2568+
nfp_net_ipsec_init(nn);
25672569
}
25682570

25692571
nfp_net_vecs_init(nn);
@@ -2587,6 +2589,7 @@ void nfp_net_clean(struct nfp_net *nn)
25872589
return;
25882590

25892591
unregister_netdev(nn->dp.netdev);
2592+
nfp_net_ipsec_clean(nn);
25902593
nfp_ccm_mbox_clean(nn);
25912594
nfp_net_reconfig_wait_posted(nn);
25922595
}

0 commit comments

Comments
 (0)