Skip to content

Commit a43dce9

Browse files
committed
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec-next
Steffen Klassert says: ==================== pull request (net-next): ipsec-next 2017-08-21 1) Support RX checksum with IPsec crypto offload for esp4/esp6. From Ilan Tayari. 2) Fixup IPv6 checksums when doing IPsec crypto offload. From Yossi Kuperman. 3) Auto load the xfrom offload modules if a user installs a SA that requests IPsec offload. From Ilan Tayari. 4) Clear RX offload informations in xfrm_input to not confuse the TX path with stale offload informations. From Ilan Tayari. 5) Allow IPsec GSO for local sockets if the crypto operation will be offloaded. 6) Support setting of an output mark to the xfrm_state. This mark can be used to to do the tunnel route lookup. From Lorenzo Colitti. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
2 parents 0c45d7f + 077fbac commit a43dce9

File tree

16 files changed

+121
-37
lines changed

16 files changed

+121
-37
lines changed

include/net/xfrm.h

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@
4343
MODULE_ALIAS("xfrm-mode-" __stringify(family) "-" __stringify(encap))
4444
#define MODULE_ALIAS_XFRM_TYPE(family, proto) \
4545
MODULE_ALIAS("xfrm-type-" __stringify(family) "-" __stringify(proto))
46+
#define MODULE_ALIAS_XFRM_OFFLOAD_TYPE(family, proto) \
47+
MODULE_ALIAS("xfrm-offload-" __stringify(family) "-" __stringify(proto))
4648

4749
#ifdef CONFIG_XFRM_STATISTICS
4850
#define XFRM_INC_STATS(net, field) SNMP_INC_STATS((net)->mib.xfrm_statistics, field)
@@ -163,6 +165,7 @@ struct xfrm_state {
163165
int header_len;
164166
int trailer_len;
165167
u32 extra_flags;
168+
u32 output_mark;
166169
} props;
167170

168171
struct xfrm_lifetime_cfg lft;
@@ -296,10 +299,12 @@ struct xfrm_policy_afinfo {
296299
struct dst_entry *(*dst_lookup)(struct net *net,
297300
int tos, int oif,
298301
const xfrm_address_t *saddr,
299-
const xfrm_address_t *daddr);
302+
const xfrm_address_t *daddr,
303+
u32 mark);
300304
int (*get_saddr)(struct net *net, int oif,
301305
xfrm_address_t *saddr,
302-
xfrm_address_t *daddr);
306+
xfrm_address_t *daddr,
307+
u32 mark);
303308
void (*decode_session)(struct sk_buff *skb,
304309
struct flowi *fl,
305310
int reverse);
@@ -1558,7 +1563,7 @@ void xfrm_spd_getinfo(struct net *net, struct xfrmk_spdinfo *si);
15581563
u32 xfrm_replay_seqhi(struct xfrm_state *x, __be32 net_seq);
15591564
int xfrm_init_replay(struct xfrm_state *x);
15601565
int xfrm_state_mtu(struct xfrm_state *x, int mtu);
1561-
int __xfrm_init_state(struct xfrm_state *x, bool init_replay);
1566+
int __xfrm_init_state(struct xfrm_state *x, bool init_replay, bool offload);
15621567
int xfrm_init_state(struct xfrm_state *x);
15631568
int xfrm_prepare_input(struct xfrm_state *x, struct sk_buff *skb);
15641569
int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type);
@@ -1638,7 +1643,7 @@ static inline int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb)
16381643
struct dst_entry *__xfrm_dst_lookup(struct net *net, int tos, int oif,
16391644
const xfrm_address_t *saddr,
16401645
const xfrm_address_t *daddr,
1641-
int family);
1646+
int family, u32 mark);
16421647

16431648
struct xfrm_policy *xfrm_policy_alloc(struct net *net, gfp_t gfp);
16441649

@@ -1856,6 +1861,20 @@ int xfrm_dev_state_add(struct net *net, struct xfrm_state *x,
18561861
struct xfrm_user_offload *xuo);
18571862
bool xfrm_dev_offload_ok(struct sk_buff *skb, struct xfrm_state *x);
18581863

1864+
static inline bool xfrm_dst_offload_ok(struct dst_entry *dst)
1865+
{
1866+
struct xfrm_state *x = dst->xfrm;
1867+
1868+
if (!x || !x->type_offload)
1869+
return false;
1870+
1871+
if (x->xso.offload_handle && (x->xso.dev == dst->path->dev) &&
1872+
!dst->child->xfrm)
1873+
return true;
1874+
1875+
return false;
1876+
}
1877+
18591878
static inline void xfrm_dev_state_delete(struct xfrm_state *x)
18601879
{
18611880
struct xfrm_state_offload *xso = &x->xso;
@@ -1898,6 +1917,11 @@ static inline bool xfrm_dev_offload_ok(struct sk_buff *skb, struct xfrm_state *x
18981917
{
18991918
return false;
19001919
}
1920+
1921+
static inline bool xfrm_dst_offload_ok(struct dst_entry *dst)
1922+
{
1923+
return false;
1924+
}
19011925
#endif
19021926

19031927
static inline int xfrm_mark_get(struct nlattr **attrs, struct xfrm_mark *m)

include/uapi/linux/xfrm.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,7 @@ enum xfrm_attr_type_t {
304304
XFRMA_ADDRESS_FILTER, /* struct xfrm_address_filter */
305305
XFRMA_PAD,
306306
XFRMA_OFFLOAD_DEV, /* struct xfrm_state_offload */
307+
XFRMA_OUTPUT_MARK, /* __u32 */
307308
__XFRMA_MAX
308309

309310
#define XFRMA_MAX (__XFRMA_MAX - 1)

net/core/sock.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1776,7 +1776,7 @@ void sk_setup_caps(struct sock *sk, struct dst_entry *dst)
17761776
sk->sk_route_caps |= NETIF_F_GSO_SOFTWARE;
17771777
sk->sk_route_caps &= ~sk->sk_route_nocaps;
17781778
if (sk_can_gso(sk)) {
1779-
if (dst->header_len) {
1779+
if (dst->header_len && !xfrm_dst_offload_ok(dst)) {
17801780
sk->sk_route_caps &= ~NETIF_F_GSO_MASK;
17811781
} else {
17821782
sk->sk_route_caps |= NETIF_F_SG | NETIF_F_HW_CSUM;

net/ipv4/esp4.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -510,7 +510,8 @@ int esp_input_done2(struct sk_buff *skb, int err)
510510
int elen = skb->len - hlen;
511511
int ihl;
512512
u8 nexthdr[2];
513-
int padlen;
513+
int padlen, trimlen;
514+
__wsum csumdiff;
514515

515516
if (!xo || (xo && !(xo->flags & CRYPTO_DONE)))
516517
kfree(ESP_SKB_CB(skb)->tmp);
@@ -568,8 +569,15 @@ int esp_input_done2(struct sk_buff *skb, int err)
568569
skb->ip_summed = CHECKSUM_UNNECESSARY;
569570
}
570571

571-
pskb_trim(skb, skb->len - alen - padlen - 2);
572-
__skb_pull(skb, hlen);
572+
trimlen = alen + padlen + 2;
573+
if (skb->ip_summed == CHECKSUM_COMPLETE) {
574+
csumdiff = skb_checksum(skb, skb->len - trimlen, trimlen, 0);
575+
skb->csum = csum_block_sub(skb->csum, csumdiff,
576+
skb->len - trimlen);
577+
}
578+
pskb_trim(skb, skb->len - trimlen);
579+
580+
skb_pull_rcsum(skb, hlen);
573581
if (x->props.mode == XFRM_MODE_TUNNEL)
574582
skb_reset_transport_header(skb);
575583
else

net/ipv4/esp4_offload.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,11 +182,13 @@ static struct sk_buff *esp4_gso_segment(struct sk_buff *skb,
182182
static int esp_input_tail(struct xfrm_state *x, struct sk_buff *skb)
183183
{
184184
struct crypto_aead *aead = x->data;
185+
struct xfrm_offload *xo = xfrm_offload(skb);
185186

186187
if (!pskb_may_pull(skb, sizeof(struct ip_esp_hdr) + crypto_aead_ivsize(aead)))
187188
return -EINVAL;
188189

189-
skb->ip_summed = CHECKSUM_NONE;
190+
if (!(xo->flags & CRYPTO_DONE))
191+
skb->ip_summed = CHECKSUM_NONE;
190192

191193
return esp_input_done2(skb, 0);
192194
}
@@ -303,3 +305,4 @@ module_init(esp4_offload_init);
303305
module_exit(esp4_offload_exit);
304306
MODULE_LICENSE("GPL");
305307
MODULE_AUTHOR("Steffen Klassert <steffen.klassert@secunet.com>");
308+
MODULE_ALIAS_XFRM_OFFLOAD_TYPE(AF_INET, XFRM_PROTO_ESP);

net/ipv4/xfrm4_policy.c

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,16 @@
2020
static struct dst_entry *__xfrm4_dst_lookup(struct net *net, struct flowi4 *fl4,
2121
int tos, int oif,
2222
const xfrm_address_t *saddr,
23-
const xfrm_address_t *daddr)
23+
const xfrm_address_t *daddr,
24+
u32 mark)
2425
{
2526
struct rtable *rt;
2627

2728
memset(fl4, 0, sizeof(*fl4));
2829
fl4->daddr = daddr->a4;
2930
fl4->flowi4_tos = tos;
3031
fl4->flowi4_oif = l3mdev_master_ifindex_by_index(net, oif);
32+
fl4->flowi4_mark = mark;
3133
if (saddr)
3234
fl4->saddr = saddr->a4;
3335

@@ -42,20 +44,22 @@ static struct dst_entry *__xfrm4_dst_lookup(struct net *net, struct flowi4 *fl4,
4244

4345
static struct dst_entry *xfrm4_dst_lookup(struct net *net, int tos, int oif,
4446
const xfrm_address_t *saddr,
45-
const xfrm_address_t *daddr)
47+
const xfrm_address_t *daddr,
48+
u32 mark)
4649
{
4750
struct flowi4 fl4;
4851

49-
return __xfrm4_dst_lookup(net, &fl4, tos, oif, saddr, daddr);
52+
return __xfrm4_dst_lookup(net, &fl4, tos, oif, saddr, daddr, mark);
5053
}
5154

5255
static int xfrm4_get_saddr(struct net *net, int oif,
53-
xfrm_address_t *saddr, xfrm_address_t *daddr)
56+
xfrm_address_t *saddr, xfrm_address_t *daddr,
57+
u32 mark)
5458
{
5559
struct dst_entry *dst;
5660
struct flowi4 fl4;
5761

58-
dst = __xfrm4_dst_lookup(net, &fl4, 0, oif, NULL, daddr);
62+
dst = __xfrm4_dst_lookup(net, &fl4, 0, oif, NULL, daddr, mark);
5963
if (IS_ERR(dst))
6064
return -EHOSTUNREACH;
6165

net/ipv6/esp6.c

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -470,7 +470,8 @@ int esp6_input_done2(struct sk_buff *skb, int err)
470470
int hlen = sizeof(struct ip_esp_hdr) + crypto_aead_ivsize(aead);
471471
int elen = skb->len - hlen;
472472
int hdr_len = skb_network_header_len(skb);
473-
int padlen;
473+
int padlen, trimlen;
474+
__wsum csumdiff;
474475
u8 nexthdr[2];
475476

476477
if (!xo || (xo && !(xo->flags & CRYPTO_DONE)))
@@ -492,8 +493,17 @@ int esp6_input_done2(struct sk_buff *skb, int err)
492493

493494
/* ... check padding bits here. Silly. :-) */
494495

495-
pskb_trim(skb, skb->len - alen - padlen - 2);
496-
__skb_pull(skb, hlen);
496+
trimlen = alen + padlen + 2;
497+
if (skb->ip_summed == CHECKSUM_COMPLETE) {
498+
skb_postpull_rcsum(skb, skb_network_header(skb),
499+
skb_network_header_len(skb));
500+
csumdiff = skb_checksum(skb, skb->len - trimlen, trimlen, 0);
501+
skb->csum = csum_block_sub(skb->csum, csumdiff,
502+
skb->len - trimlen);
503+
}
504+
pskb_trim(skb, skb->len - trimlen);
505+
506+
skb_pull_rcsum(skb, hlen);
497507
if (x->props.mode == XFRM_MODE_TUNNEL)
498508
skb_reset_transport_header(skb);
499509
else

net/ipv6/esp6_offload.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,11 +209,13 @@ static struct sk_buff *esp6_gso_segment(struct sk_buff *skb,
209209
static int esp6_input_tail(struct xfrm_state *x, struct sk_buff *skb)
210210
{
211211
struct crypto_aead *aead = x->data;
212+
struct xfrm_offload *xo = xfrm_offload(skb);
212213

213214
if (!pskb_may_pull(skb, sizeof(struct ip_esp_hdr) + crypto_aead_ivsize(aead)))
214215
return -EINVAL;
215216

216-
skb->ip_summed = CHECKSUM_NONE;
217+
if (!(xo->flags & CRYPTO_DONE))
218+
skb->ip_summed = CHECKSUM_NONE;
217219

218220
return esp6_input_done2(skb, 0);
219221
}
@@ -332,3 +334,4 @@ module_init(esp6_offload_init);
332334
module_exit(esp6_offload_exit);
333335
MODULE_LICENSE("GPL");
334336
MODULE_AUTHOR("Steffen Klassert <steffen.klassert@secunet.com>");
337+
MODULE_ALIAS_XFRM_OFFLOAD_TYPE(AF_INET6, XFRM_PROTO_ESP);

net/ipv6/xfrm6_input.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ EXPORT_SYMBOL(xfrm6_rcv_spi);
3434
int xfrm6_transport_finish(struct sk_buff *skb, int async)
3535
{
3636
struct xfrm_offload *xo = xfrm_offload(skb);
37+
int nhlen = skb->data - skb_network_header(skb);
3738

3839
skb_network_header(skb)[IP6CB(skb)->nhoff] =
3940
XFRM_MODE_SKB_CB(skb)->protocol;
@@ -43,8 +44,9 @@ int xfrm6_transport_finish(struct sk_buff *skb, int async)
4344
return 1;
4445
#endif
4546

46-
__skb_push(skb, skb->data - skb_network_header(skb));
47+
__skb_push(skb, nhlen);
4748
ipv6_hdr(skb)->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
49+
skb_postpush_rcsum(skb, skb_network_header(skb), nhlen);
4850

4951
if (xo && (xo->flags & XFRM_GRO)) {
5052
skb_mac_header_rebuild(skb);

net/ipv6/xfrm6_policy.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@
2727

2828
static struct dst_entry *xfrm6_dst_lookup(struct net *net, int tos, int oif,
2929
const xfrm_address_t *saddr,
30-
const xfrm_address_t *daddr)
30+
const xfrm_address_t *daddr,
31+
u32 mark)
3132
{
3233
struct flowi6 fl6;
3334
struct dst_entry *dst;
@@ -36,6 +37,7 @@ static struct dst_entry *xfrm6_dst_lookup(struct net *net, int tos, int oif,
3637
memset(&fl6, 0, sizeof(fl6));
3738
fl6.flowi6_oif = l3mdev_master_ifindex_by_index(net, oif);
3839
fl6.flowi6_flags = FLOWI_FLAG_SKIP_NH_OIF;
40+
fl6.flowi6_mark = mark;
3941
memcpy(&fl6.daddr, daddr, sizeof(fl6.daddr));
4042
if (saddr)
4143
memcpy(&fl6.saddr, saddr, sizeof(fl6.saddr));
@@ -52,12 +54,13 @@ static struct dst_entry *xfrm6_dst_lookup(struct net *net, int tos, int oif,
5254
}
5355

5456
static int xfrm6_get_saddr(struct net *net, int oif,
55-
xfrm_address_t *saddr, xfrm_address_t *daddr)
57+
xfrm_address_t *saddr, xfrm_address_t *daddr,
58+
u32 mark)
5659
{
5760
struct dst_entry *dst;
5861
struct net_device *dev;
5962

60-
dst = xfrm6_dst_lookup(net, 0, oif, NULL, daddr);
63+
dst = xfrm6_dst_lookup(net, 0, oif, NULL, daddr, mark);
6164
if (IS_ERR(dst))
6265
return -EHOSTUNREACH;
6366

net/xfrm/xfrm_device.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ int xfrm_dev_state_add(struct net *net, struct xfrm_state *x,
6363
xfrm_address_t *daddr;
6464

6565
if (!x->type_offload)
66-
return 0;
66+
return -EINVAL;
6767

6868
/* We don't yet support UDP encapsulation, TFC padding and ESN. */
6969
if (x->encap || x->tfcpad || (x->props.flags & XFRM_STATE_ESN))
@@ -79,7 +79,8 @@ int xfrm_dev_state_add(struct net *net, struct xfrm_state *x,
7979
daddr = &x->props.saddr;
8080
}
8181

82-
dst = __xfrm_dst_lookup(net, 0, 0, saddr, daddr, x->props.family);
82+
dst = __xfrm_dst_lookup(net, 0, 0, saddr, daddr,
83+
x->props.family, x->props.output_mark);
8384
if (IS_ERR(dst))
8485
return 0;
8586

net/xfrm/xfrm_input.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
424424
nf_reset(skb);
425425

426426
if (decaps) {
427+
skb->sp->olen = 0;
427428
skb_dst_drop(skb);
428429
gro_cells_receive(&gro_cells, skb);
429430
return 0;
@@ -434,6 +435,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
434435

435436
err = x->inner_mode->afinfo->transport_finish(skb, xfrm_gro || async);
436437
if (xfrm_gro) {
438+
skb->sp->olen = 0;
437439
skb_dst_drop(skb);
438440
gro_cells_receive(&gro_cells, skb);
439441
return err;

net/xfrm/xfrm_output.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ static int xfrm_output_one(struct sk_buff *skb, int err)
6666
goto error_nolock;
6767
}
6868

69+
if (x->props.output_mark)
70+
skb->mark = x->props.output_mark;
71+
6972
err = x->outer_mode->output(x, skb);
7073
if (err) {
7174
XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEMODEERROR);

0 commit comments

Comments
 (0)