Skip to content

Commit

Permalink
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/gi…
Browse files Browse the repository at this point in the history
…t/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>
  • Loading branch information
David S. Miller committed Aug 21, 2017
2 parents 0c45d7f + 077fbac commit a43dce9
Show file tree
Hide file tree
Showing 16 changed files with 121 additions and 37 deletions.
32 changes: 28 additions & 4 deletions include/net/xfrm.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@
MODULE_ALIAS("xfrm-mode-" __stringify(family) "-" __stringify(encap))
#define MODULE_ALIAS_XFRM_TYPE(family, proto) \
MODULE_ALIAS("xfrm-type-" __stringify(family) "-" __stringify(proto))
#define MODULE_ALIAS_XFRM_OFFLOAD_TYPE(family, proto) \
MODULE_ALIAS("xfrm-offload-" __stringify(family) "-" __stringify(proto))

#ifdef CONFIG_XFRM_STATISTICS
#define XFRM_INC_STATS(net, field) SNMP_INC_STATS((net)->mib.xfrm_statistics, field)
Expand Down Expand Up @@ -163,6 +165,7 @@ struct xfrm_state {
int header_len;
int trailer_len;
u32 extra_flags;
u32 output_mark;
} props;

struct xfrm_lifetime_cfg lft;
Expand Down Expand Up @@ -296,10 +299,12 @@ struct xfrm_policy_afinfo {
struct dst_entry *(*dst_lookup)(struct net *net,
int tos, int oif,
const xfrm_address_t *saddr,
const xfrm_address_t *daddr);
const xfrm_address_t *daddr,
u32 mark);
int (*get_saddr)(struct net *net, int oif,
xfrm_address_t *saddr,
xfrm_address_t *daddr);
xfrm_address_t *daddr,
u32 mark);
void (*decode_session)(struct sk_buff *skb,
struct flowi *fl,
int reverse);
Expand Down Expand Up @@ -1558,7 +1563,7 @@ void xfrm_spd_getinfo(struct net *net, struct xfrmk_spdinfo *si);
u32 xfrm_replay_seqhi(struct xfrm_state *x, __be32 net_seq);
int xfrm_init_replay(struct xfrm_state *x);
int xfrm_state_mtu(struct xfrm_state *x, int mtu);
int __xfrm_init_state(struct xfrm_state *x, bool init_replay);
int __xfrm_init_state(struct xfrm_state *x, bool init_replay, bool offload);
int xfrm_init_state(struct xfrm_state *x);
int xfrm_prepare_input(struct xfrm_state *x, struct sk_buff *skb);
int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type);
Expand Down Expand Up @@ -1638,7 +1643,7 @@ static inline int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb)
struct dst_entry *__xfrm_dst_lookup(struct net *net, int tos, int oif,
const xfrm_address_t *saddr,
const xfrm_address_t *daddr,
int family);
int family, u32 mark);

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

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

static inline bool xfrm_dst_offload_ok(struct dst_entry *dst)
{
struct xfrm_state *x = dst->xfrm;

if (!x || !x->type_offload)
return false;

if (x->xso.offload_handle && (x->xso.dev == dst->path->dev) &&
!dst->child->xfrm)
return true;

return false;
}

static inline void xfrm_dev_state_delete(struct xfrm_state *x)
{
struct xfrm_state_offload *xso = &x->xso;
Expand Down Expand Up @@ -1898,6 +1917,11 @@ static inline bool xfrm_dev_offload_ok(struct sk_buff *skb, struct xfrm_state *x
{
return false;
}

static inline bool xfrm_dst_offload_ok(struct dst_entry *dst)
{
return false;
}
#endif

static inline int xfrm_mark_get(struct nlattr **attrs, struct xfrm_mark *m)
Expand Down
1 change: 1 addition & 0 deletions include/uapi/linux/xfrm.h
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@ enum xfrm_attr_type_t {
XFRMA_ADDRESS_FILTER, /* struct xfrm_address_filter */
XFRMA_PAD,
XFRMA_OFFLOAD_DEV, /* struct xfrm_state_offload */
XFRMA_OUTPUT_MARK, /* __u32 */
__XFRMA_MAX

#define XFRMA_MAX (__XFRMA_MAX - 1)
Expand Down
2 changes: 1 addition & 1 deletion net/core/sock.c
Original file line number Diff line number Diff line change
Expand Up @@ -1776,7 +1776,7 @@ void sk_setup_caps(struct sock *sk, struct dst_entry *dst)
sk->sk_route_caps |= NETIF_F_GSO_SOFTWARE;
sk->sk_route_caps &= ~sk->sk_route_nocaps;
if (sk_can_gso(sk)) {
if (dst->header_len) {
if (dst->header_len && !xfrm_dst_offload_ok(dst)) {
sk->sk_route_caps &= ~NETIF_F_GSO_MASK;
} else {
sk->sk_route_caps |= NETIF_F_SG | NETIF_F_HW_CSUM;
Expand Down
14 changes: 11 additions & 3 deletions net/ipv4/esp4.c
Original file line number Diff line number Diff line change
Expand Up @@ -510,7 +510,8 @@ int esp_input_done2(struct sk_buff *skb, int err)
int elen = skb->len - hlen;
int ihl;
u8 nexthdr[2];
int padlen;
int padlen, trimlen;
__wsum csumdiff;

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

pskb_trim(skb, skb->len - alen - padlen - 2);
__skb_pull(skb, hlen);
trimlen = alen + padlen + 2;
if (skb->ip_summed == CHECKSUM_COMPLETE) {
csumdiff = skb_checksum(skb, skb->len - trimlen, trimlen, 0);
skb->csum = csum_block_sub(skb->csum, csumdiff,
skb->len - trimlen);
}
pskb_trim(skb, skb->len - trimlen);

skb_pull_rcsum(skb, hlen);
if (x->props.mode == XFRM_MODE_TUNNEL)
skb_reset_transport_header(skb);
else
Expand Down
5 changes: 4 additions & 1 deletion net/ipv4/esp4_offload.c
Original file line number Diff line number Diff line change
Expand Up @@ -182,11 +182,13 @@ static struct sk_buff *esp4_gso_segment(struct sk_buff *skb,
static int esp_input_tail(struct xfrm_state *x, struct sk_buff *skb)
{
struct crypto_aead *aead = x->data;
struct xfrm_offload *xo = xfrm_offload(skb);

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

skb->ip_summed = CHECKSUM_NONE;
if (!(xo->flags & CRYPTO_DONE))
skb->ip_summed = CHECKSUM_NONE;

return esp_input_done2(skb, 0);
}
Expand Down Expand Up @@ -303,3 +305,4 @@ module_init(esp4_offload_init);
module_exit(esp4_offload_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Steffen Klassert <steffen.klassert@secunet.com>");
MODULE_ALIAS_XFRM_OFFLOAD_TYPE(AF_INET, XFRM_PROTO_ESP);
14 changes: 9 additions & 5 deletions net/ipv4/xfrm4_policy.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,16 @@
static struct dst_entry *__xfrm4_dst_lookup(struct net *net, struct flowi4 *fl4,
int tos, int oif,
const xfrm_address_t *saddr,
const xfrm_address_t *daddr)
const xfrm_address_t *daddr,
u32 mark)
{
struct rtable *rt;

memset(fl4, 0, sizeof(*fl4));
fl4->daddr = daddr->a4;
fl4->flowi4_tos = tos;
fl4->flowi4_oif = l3mdev_master_ifindex_by_index(net, oif);
fl4->flowi4_mark = mark;
if (saddr)
fl4->saddr = saddr->a4;

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

static struct dst_entry *xfrm4_dst_lookup(struct net *net, int tos, int oif,
const xfrm_address_t *saddr,
const xfrm_address_t *daddr)
const xfrm_address_t *daddr,
u32 mark)
{
struct flowi4 fl4;

return __xfrm4_dst_lookup(net, &fl4, tos, oif, saddr, daddr);
return __xfrm4_dst_lookup(net, &fl4, tos, oif, saddr, daddr, mark);
}

static int xfrm4_get_saddr(struct net *net, int oif,
xfrm_address_t *saddr, xfrm_address_t *daddr)
xfrm_address_t *saddr, xfrm_address_t *daddr,
u32 mark)
{
struct dst_entry *dst;
struct flowi4 fl4;

dst = __xfrm4_dst_lookup(net, &fl4, 0, oif, NULL, daddr);
dst = __xfrm4_dst_lookup(net, &fl4, 0, oif, NULL, daddr, mark);
if (IS_ERR(dst))
return -EHOSTUNREACH;

Expand Down
16 changes: 13 additions & 3 deletions net/ipv6/esp6.c
Original file line number Diff line number Diff line change
Expand Up @@ -470,7 +470,8 @@ int esp6_input_done2(struct sk_buff *skb, int err)
int hlen = sizeof(struct ip_esp_hdr) + crypto_aead_ivsize(aead);
int elen = skb->len - hlen;
int hdr_len = skb_network_header_len(skb);
int padlen;
int padlen, trimlen;
__wsum csumdiff;
u8 nexthdr[2];

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

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

pskb_trim(skb, skb->len - alen - padlen - 2);
__skb_pull(skb, hlen);
trimlen = alen + padlen + 2;
if (skb->ip_summed == CHECKSUM_COMPLETE) {
skb_postpull_rcsum(skb, skb_network_header(skb),
skb_network_header_len(skb));
csumdiff = skb_checksum(skb, skb->len - trimlen, trimlen, 0);
skb->csum = csum_block_sub(skb->csum, csumdiff,
skb->len - trimlen);
}
pskb_trim(skb, skb->len - trimlen);

skb_pull_rcsum(skb, hlen);
if (x->props.mode == XFRM_MODE_TUNNEL)
skb_reset_transport_header(skb);
else
Expand Down
5 changes: 4 additions & 1 deletion net/ipv6/esp6_offload.c
Original file line number Diff line number Diff line change
Expand Up @@ -209,11 +209,13 @@ static struct sk_buff *esp6_gso_segment(struct sk_buff *skb,
static int esp6_input_tail(struct xfrm_state *x, struct sk_buff *skb)
{
struct crypto_aead *aead = x->data;
struct xfrm_offload *xo = xfrm_offload(skb);

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

skb->ip_summed = CHECKSUM_NONE;
if (!(xo->flags & CRYPTO_DONE))
skb->ip_summed = CHECKSUM_NONE;

return esp6_input_done2(skb, 0);
}
Expand Down Expand Up @@ -332,3 +334,4 @@ module_init(esp6_offload_init);
module_exit(esp6_offload_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Steffen Klassert <steffen.klassert@secunet.com>");
MODULE_ALIAS_XFRM_OFFLOAD_TYPE(AF_INET6, XFRM_PROTO_ESP);
4 changes: 3 additions & 1 deletion net/ipv6/xfrm6_input.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ EXPORT_SYMBOL(xfrm6_rcv_spi);
int xfrm6_transport_finish(struct sk_buff *skb, int async)
{
struct xfrm_offload *xo = xfrm_offload(skb);
int nhlen = skb->data - skb_network_header(skb);

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

__skb_push(skb, skb->data - skb_network_header(skb));
__skb_push(skb, nhlen);
ipv6_hdr(skb)->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
skb_postpush_rcsum(skb, skb_network_header(skb), nhlen);

if (xo && (xo->flags & XFRM_GRO)) {
skb_mac_header_rebuild(skb);
Expand Down
9 changes: 6 additions & 3 deletions net/ipv6/xfrm6_policy.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@

static struct dst_entry *xfrm6_dst_lookup(struct net *net, int tos, int oif,
const xfrm_address_t *saddr,
const xfrm_address_t *daddr)
const xfrm_address_t *daddr,
u32 mark)
{
struct flowi6 fl6;
struct dst_entry *dst;
Expand All @@ -36,6 +37,7 @@ static struct dst_entry *xfrm6_dst_lookup(struct net *net, int tos, int oif,
memset(&fl6, 0, sizeof(fl6));
fl6.flowi6_oif = l3mdev_master_ifindex_by_index(net, oif);
fl6.flowi6_flags = FLOWI_FLAG_SKIP_NH_OIF;
fl6.flowi6_mark = mark;
memcpy(&fl6.daddr, daddr, sizeof(fl6.daddr));
if (saddr)
memcpy(&fl6.saddr, saddr, sizeof(fl6.saddr));
Expand All @@ -52,12 +54,13 @@ static struct dst_entry *xfrm6_dst_lookup(struct net *net, int tos, int oif,
}

static int xfrm6_get_saddr(struct net *net, int oif,
xfrm_address_t *saddr, xfrm_address_t *daddr)
xfrm_address_t *saddr, xfrm_address_t *daddr,
u32 mark)
{
struct dst_entry *dst;
struct net_device *dev;

dst = xfrm6_dst_lookup(net, 0, oif, NULL, daddr);
dst = xfrm6_dst_lookup(net, 0, oif, NULL, daddr, mark);
if (IS_ERR(dst))
return -EHOSTUNREACH;

Expand Down
5 changes: 3 additions & 2 deletions net/xfrm/xfrm_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ int xfrm_dev_state_add(struct net *net, struct xfrm_state *x,
xfrm_address_t *daddr;

if (!x->type_offload)
return 0;
return -EINVAL;

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

dst = __xfrm_dst_lookup(net, 0, 0, saddr, daddr, x->props.family);
dst = __xfrm_dst_lookup(net, 0, 0, saddr, daddr,
x->props.family, x->props.output_mark);
if (IS_ERR(dst))
return 0;

Expand Down
2 changes: 2 additions & 0 deletions net/xfrm/xfrm_input.c
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
nf_reset(skb);

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

err = x->inner_mode->afinfo->transport_finish(skb, xfrm_gro || async);
if (xfrm_gro) {
skb->sp->olen = 0;
skb_dst_drop(skb);
gro_cells_receive(&gro_cells, skb);
return err;
Expand Down
3 changes: 3 additions & 0 deletions net/xfrm/xfrm_output.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ static int xfrm_output_one(struct sk_buff *skb, int err)
goto error_nolock;
}

if (x->props.output_mark)
skb->mark = x->props.output_mark;

err = x->outer_mode->output(x, skb);
if (err) {
XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEMODEERROR);
Expand Down
Loading

0 comments on commit a43dce9

Please sign in to comment.