Skip to content

Commit d77e38e

Browse files
committed
xfrm: Add an IPsec hardware offloading API
This patch adds all the bits that are needed to do IPsec hardware offload for IPsec states and ESP packets. We add xfrmdev_ops to the net_device. xfrmdev_ops has function pointers that are needed to manage the xfrm states in the hardware and to do a per packet offloading decision. Joint work with: Ilan Tayari <[email protected]> Guy Shapiro <[email protected]> Yossi Kuperman <[email protected]> Signed-off-by: Guy Shapiro <[email protected]> Signed-off-by: Ilan Tayari <[email protected]> Signed-off-by: Yossi Kuperman <[email protected]> Signed-off-by: Steffen Klassert <[email protected]>
1 parent c35fe41 commit d77e38e

File tree

14 files changed

+424
-24
lines changed

14 files changed

+424
-24
lines changed

include/linux/netdevice.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -824,6 +824,16 @@ struct netdev_xdp {
824824
};
825825
};
826826

827+
#ifdef CONFIG_XFRM_OFFLOAD
828+
struct xfrmdev_ops {
829+
int (*xdo_dev_state_add) (struct xfrm_state *x);
830+
void (*xdo_dev_state_delete) (struct xfrm_state *x);
831+
void (*xdo_dev_state_free) (struct xfrm_state *x);
832+
bool (*xdo_dev_offload_ok) (struct sk_buff *skb,
833+
struct xfrm_state *x);
834+
};
835+
#endif
836+
827837
/*
828838
* This structure defines the management hooks for network devices.
829839
* The following hooks can be defined; unless noted otherwise, they are
@@ -1697,6 +1707,10 @@ struct net_device {
16971707
const struct ndisc_ops *ndisc_ops;
16981708
#endif
16991709

1710+
#ifdef CONFIG_XFRM
1711+
const struct xfrmdev_ops *xfrmdev_ops;
1712+
#endif
1713+
17001714
const struct header_ops *header_ops;
17011715

17021716
unsigned int flags;

include/net/xfrm.h

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,13 @@ struct xfrm_state_walk {
120120
struct xfrm_address_filter *filter;
121121
};
122122

123+
struct xfrm_state_offload {
124+
struct net_device *dev;
125+
unsigned long offload_handle;
126+
unsigned int num_exthdrs;
127+
u8 flags;
128+
};
129+
123130
/* Full description of state of transformer. */
124131
struct xfrm_state {
125132
possible_net_t xs_net;
@@ -207,6 +214,8 @@ struct xfrm_state {
207214
struct xfrm_lifetime_cur curlft;
208215
struct tasklet_hrtimer mtimer;
209216

217+
struct xfrm_state_offload xso;
218+
210219
/* used to fix curlft->add_time when changing date */
211220
long saved_tmo;
212221

@@ -1453,7 +1462,6 @@ struct xfrm6_tunnel {
14531462
void xfrm_init(void);
14541463
void xfrm4_init(void);
14551464
int xfrm_state_init(struct net *net);
1456-
void xfrm_dev_init(void);
14571465
void xfrm_state_fini(struct net *net);
14581466
void xfrm4_state_init(void);
14591467
void xfrm4_protocol_init(void);
@@ -1559,6 +1567,7 @@ struct xfrmk_spdinfo {
15591567
struct xfrm_state *xfrm_find_acq_byseq(struct net *net, u32 mark, u32 seq);
15601568
int xfrm_state_delete(struct xfrm_state *x);
15611569
int xfrm_state_flush(struct net *net, u8 proto, bool task_valid);
1570+
int xfrm_dev_state_flush(struct net *net, struct net_device *dev, bool task_valid);
15621571
void xfrm_sad_getinfo(struct net *net, struct xfrmk_sadinfo *si);
15631572
void xfrm_spd_getinfo(struct net *net, struct xfrmk_spdinfo *si);
15641573
u32 xfrm_replay_seqhi(struct xfrm_state *x, __be32 net_seq);
@@ -1641,6 +1650,11 @@ static inline int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb)
16411650
}
16421651
#endif
16431652

1653+
struct dst_entry *__xfrm_dst_lookup(struct net *net, int tos, int oif,
1654+
const xfrm_address_t *saddr,
1655+
const xfrm_address_t *daddr,
1656+
int family);
1657+
16441658
struct xfrm_policy *xfrm_policy_alloc(struct net *net, gfp_t gfp);
16451659

16461660
void xfrm_policy_walk_init(struct xfrm_policy_walk *walk, u8 type);
@@ -1846,6 +1860,55 @@ static inline struct xfrm_offload *xfrm_offload(struct sk_buff *skb)
18461860
}
18471861
#endif
18481862

1863+
#ifdef CONFIG_XFRM_OFFLOAD
1864+
void __net_init xfrm_dev_init(void);
1865+
int xfrm_dev_state_add(struct net *net, struct xfrm_state *x,
1866+
struct xfrm_user_offload *xuo);
1867+
bool xfrm_dev_offload_ok(struct sk_buff *skb, struct xfrm_state *x);
1868+
1869+
static inline void xfrm_dev_state_delete(struct xfrm_state *x)
1870+
{
1871+
struct xfrm_state_offload *xso = &x->xso;
1872+
1873+
if (xso->dev)
1874+
xso->dev->xfrmdev_ops->xdo_dev_state_delete(x);
1875+
}
1876+
1877+
static inline void xfrm_dev_state_free(struct xfrm_state *x)
1878+
{
1879+
struct xfrm_state_offload *xso = &x->xso;
1880+
struct net_device *dev = xso->dev;
1881+
1882+
if (dev && dev->xfrmdev_ops) {
1883+
dev->xfrmdev_ops->xdo_dev_state_free(x);
1884+
xso->dev = NULL;
1885+
dev_put(dev);
1886+
}
1887+
}
1888+
#else
1889+
static inline void __net_init xfrm_dev_init(void)
1890+
{
1891+
}
1892+
1893+
static inline int xfrm_dev_state_add(struct net *net, struct xfrm_state *x, struct xfrm_user_offload *xuo)
1894+
{
1895+
return 0;
1896+
}
1897+
1898+
static inline void xfrm_dev_state_delete(struct xfrm_state *x)
1899+
{
1900+
}
1901+
1902+
static inline void xfrm_dev_state_free(struct xfrm_state *x)
1903+
{
1904+
}
1905+
1906+
static inline bool xfrm_dev_offload_ok(struct sk_buff *skb, struct xfrm_state *x)
1907+
{
1908+
return false;
1909+
}
1910+
#endif
1911+
18491912
static inline int xfrm_mark_get(struct nlattr **attrs, struct xfrm_mark *m)
18501913
{
18511914
if (attrs[XFRMA_MARK])

include/uapi/linux/xfrm.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,7 @@ enum xfrm_attr_type_t {
303303
XFRMA_PROTO, /* __u8 */
304304
XFRMA_ADDRESS_FILTER, /* struct xfrm_address_filter */
305305
XFRMA_PAD,
306+
XFRMA_OFFLOAD_DEV, /* struct xfrm_state_offload */
306307
__XFRMA_MAX
307308

308309
#define XFRMA_MAX (__XFRMA_MAX - 1)
@@ -494,6 +495,13 @@ struct xfrm_address_filter {
494495
__u8 dplen;
495496
};
496497

498+
struct xfrm_user_offload {
499+
int ifindex;
500+
__u8 flags;
501+
};
502+
#define XFRM_OFFLOAD_IPV6 1
503+
#define XFRM_OFFLOAD_INBOUND 2
504+
497505
#ifndef __KERNEL__
498506
/* backwards compatibility for userspace */
499507
#define XFRMGRP_ACQUIRE 1

net/ipv4/esp4.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -435,9 +435,6 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb)
435435
aead_request_set_crypt(req, sg, dsg, ivlen + clen, iv);
436436
aead_request_set_ad(req, assoclen);
437437

438-
seqno = cpu_to_be64(XFRM_SKB_CB(skb)->seq.output.low +
439-
((u64)XFRM_SKB_CB(skb)->seq.output.hi << 32));
440-
441438
memset(iv, 0, ivlen);
442439
memcpy(iv + ivlen - min(ivlen, 8), (u8 *)&seqno + 8 - min(ivlen, 8),
443440
min(ivlen, 8));
@@ -470,6 +467,7 @@ static int esp_input_done2(struct sk_buff *skb, int err)
470467
{
471468
const struct iphdr *iph;
472469
struct xfrm_state *x = xfrm_input_state(skb);
470+
struct xfrm_offload *xo = xfrm_offload(skb);
473471
struct crypto_aead *aead = x->data;
474472
int alen = crypto_aead_authsize(aead);
475473
int hlen = sizeof(struct ip_esp_hdr) + crypto_aead_ivsize(aead);
@@ -478,7 +476,8 @@ static int esp_input_done2(struct sk_buff *skb, int err)
478476
u8 nexthdr[2];
479477
int padlen;
480478

481-
kfree(ESP_SKB_CB(skb)->tmp);
479+
if (!xo || (xo && !(xo->flags & CRYPTO_DONE)))
480+
kfree(ESP_SKB_CB(skb)->tmp);
482481

483482
if (unlikely(err))
484483
goto out;

net/ipv4/xfrm4_output.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ static int xfrm4_tunnel_check_size(struct sk_buff *skb)
2929
goto out;
3030

3131
mtu = dst_mtu(skb_dst(skb));
32-
if (skb->len > mtu) {
32+
if ((!skb_is_gso(skb) && skb->len > mtu) ||
33+
(skb_is_gso(skb) && skb_gso_network_seglen(skb) > ip_skb_dst_mtu(skb->sk, skb))) {
3334
skb->protocol = htons(ETH_P_IP);
3435

3536
if (skb->sk)

net/ipv6/esp6.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,7 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb)
450450
static int esp_input_done2(struct sk_buff *skb, int err)
451451
{
452452
struct xfrm_state *x = xfrm_input_state(skb);
453+
struct xfrm_offload *xo = xfrm_offload(skb);
453454
struct crypto_aead *aead = x->data;
454455
int alen = crypto_aead_authsize(aead);
455456
int hlen = sizeof(struct ip_esp_hdr) + crypto_aead_ivsize(aead);
@@ -458,7 +459,8 @@ static int esp_input_done2(struct sk_buff *skb, int err)
458459
int padlen;
459460
u8 nexthdr[2];
460461

461-
kfree(ESP_SKB_CB(skb)->tmp);
462+
if (!xo || (xo && !(xo->flags & CRYPTO_DONE)))
463+
kfree(ESP_SKB_CB(skb)->tmp);
462464

463465
if (unlikely(err))
464466
goto out;

net/ipv6/xfrm6_output.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,11 +73,16 @@ static int xfrm6_tunnel_check_size(struct sk_buff *skb)
7373
int mtu, ret = 0;
7474
struct dst_entry *dst = skb_dst(skb);
7575

76+
if (skb->ignore_df)
77+
goto out;
78+
7679
mtu = dst_mtu(dst);
7780
if (mtu < IPV6_MIN_MTU)
7881
mtu = IPV6_MIN_MTU;
7982

80-
if (!skb->ignore_df && skb->len > mtu) {
83+
if ((!skb_is_gso(skb) && skb->len > mtu) ||
84+
(skb_is_gso(skb) &&
85+
skb_gso_network_seglen(skb) > ip6_skb_dst_mtu(skb))) {
8186
skb->dev = dst->dev;
8287
skb->protocol = htons(ETH_P_IPV6);
8388

@@ -89,7 +94,7 @@ static int xfrm6_tunnel_check_size(struct sk_buff *skb)
8994
icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
9095
ret = -EMSGSIZE;
9196
}
92-
97+
out:
9398
return ret;
9499
}
95100

net/xfrm/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44

55
obj-$(CONFIG_XFRM) := xfrm_policy.o xfrm_state.o xfrm_hash.o \
66
xfrm_input.o xfrm_output.o \
7-
xfrm_sysctl.o xfrm_replay.o xfrm_device.o
7+
xfrm_sysctl.o xfrm_replay.o
8+
obj-$(CONFIG_XFRM_OFFLOAD) += xfrm_device.o
89
obj-$(CONFIG_XFRM_STATISTICS) += xfrm_proc.o
910
obj-$(CONFIG_XFRM_ALGO) += xfrm_algo.o
1011
obj-$(CONFIG_XFRM_USER) += xfrm_user.o

0 commit comments

Comments
 (0)