Commit a43dce93 authored by David S. Miller's avatar David S. Miller

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: default avatarDavid S. Miller <davem@davemloft.net>
parents 0c45d7fe 077fbac4
...@@ -43,6 +43,8 @@ ...@@ -43,6 +43,8 @@
MODULE_ALIAS("xfrm-mode-" __stringify(family) "-" __stringify(encap)) MODULE_ALIAS("xfrm-mode-" __stringify(family) "-" __stringify(encap))
#define MODULE_ALIAS_XFRM_TYPE(family, proto) \ #define MODULE_ALIAS_XFRM_TYPE(family, proto) \
MODULE_ALIAS("xfrm-type-" __stringify(family) "-" __stringify(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 #ifdef CONFIG_XFRM_STATISTICS
#define XFRM_INC_STATS(net, field) SNMP_INC_STATS((net)->mib.xfrm_statistics, field) #define XFRM_INC_STATS(net, field) SNMP_INC_STATS((net)->mib.xfrm_statistics, field)
...@@ -163,6 +165,7 @@ struct xfrm_state { ...@@ -163,6 +165,7 @@ struct xfrm_state {
int header_len; int header_len;
int trailer_len; int trailer_len;
u32 extra_flags; u32 extra_flags;
u32 output_mark;
} props; } props;
struct xfrm_lifetime_cfg lft; struct xfrm_lifetime_cfg lft;
...@@ -296,10 +299,12 @@ struct xfrm_policy_afinfo { ...@@ -296,10 +299,12 @@ struct xfrm_policy_afinfo {
struct dst_entry *(*dst_lookup)(struct net *net, struct dst_entry *(*dst_lookup)(struct net *net,
int tos, int oif, int tos, int oif,
const xfrm_address_t *saddr, 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, int (*get_saddr)(struct net *net, int oif,
xfrm_address_t *saddr, xfrm_address_t *saddr,
xfrm_address_t *daddr); xfrm_address_t *daddr,
u32 mark);
void (*decode_session)(struct sk_buff *skb, void (*decode_session)(struct sk_buff *skb,
struct flowi *fl, struct flowi *fl,
int reverse); int reverse);
...@@ -1558,7 +1563,7 @@ void xfrm_spd_getinfo(struct net *net, struct xfrmk_spdinfo *si); ...@@ -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); u32 xfrm_replay_seqhi(struct xfrm_state *x, __be32 net_seq);
int xfrm_init_replay(struct xfrm_state *x); int xfrm_init_replay(struct xfrm_state *x);
int xfrm_state_mtu(struct xfrm_state *x, int mtu); 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_init_state(struct xfrm_state *x);
int xfrm_prepare_input(struct xfrm_state *x, struct sk_buff *skb); 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); 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) ...@@ -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, struct dst_entry *__xfrm_dst_lookup(struct net *net, int tos, int oif,
const xfrm_address_t *saddr, const xfrm_address_t *saddr,
const xfrm_address_t *daddr, const xfrm_address_t *daddr,
int family); int family, u32 mark);
struct xfrm_policy *xfrm_policy_alloc(struct net *net, gfp_t gfp); struct xfrm_policy *xfrm_policy_alloc(struct net *net, gfp_t gfp);
...@@ -1856,6 +1861,20 @@ int xfrm_dev_state_add(struct net *net, struct xfrm_state *x, ...@@ -1856,6 +1861,20 @@ int xfrm_dev_state_add(struct net *net, struct xfrm_state *x,
struct xfrm_user_offload *xuo); struct xfrm_user_offload *xuo);
bool xfrm_dev_offload_ok(struct sk_buff *skb, struct xfrm_state *x); 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) static inline void xfrm_dev_state_delete(struct xfrm_state *x)
{ {
struct xfrm_state_offload *xso = &x->xso; 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 ...@@ -1898,6 +1917,11 @@ static inline bool xfrm_dev_offload_ok(struct sk_buff *skb, struct xfrm_state *x
{ {
return false; return false;
} }
static inline bool xfrm_dst_offload_ok(struct dst_entry *dst)
{
return false;
}
#endif #endif
static inline int xfrm_mark_get(struct nlattr **attrs, struct xfrm_mark *m) static inline int xfrm_mark_get(struct nlattr **attrs, struct xfrm_mark *m)
......
...@@ -304,6 +304,7 @@ enum xfrm_attr_type_t { ...@@ -304,6 +304,7 @@ enum xfrm_attr_type_t {
XFRMA_ADDRESS_FILTER, /* struct xfrm_address_filter */ XFRMA_ADDRESS_FILTER, /* struct xfrm_address_filter */
XFRMA_PAD, XFRMA_PAD,
XFRMA_OFFLOAD_DEV, /* struct xfrm_state_offload */ XFRMA_OFFLOAD_DEV, /* struct xfrm_state_offload */
XFRMA_OUTPUT_MARK, /* __u32 */
__XFRMA_MAX __XFRMA_MAX
#define XFRMA_MAX (__XFRMA_MAX - 1) #define XFRMA_MAX (__XFRMA_MAX - 1)
......
...@@ -1776,7 +1776,7 @@ void sk_setup_caps(struct sock *sk, struct dst_entry *dst) ...@@ -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 |= NETIF_F_GSO_SOFTWARE;
sk->sk_route_caps &= ~sk->sk_route_nocaps; sk->sk_route_caps &= ~sk->sk_route_nocaps;
if (sk_can_gso(sk)) { 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; sk->sk_route_caps &= ~NETIF_F_GSO_MASK;
} else { } else {
sk->sk_route_caps |= NETIF_F_SG | NETIF_F_HW_CSUM; sk->sk_route_caps |= NETIF_F_SG | NETIF_F_HW_CSUM;
......
...@@ -510,7 +510,8 @@ int esp_input_done2(struct sk_buff *skb, int err) ...@@ -510,7 +510,8 @@ int esp_input_done2(struct sk_buff *skb, int err)
int elen = skb->len - hlen; int elen = skb->len - hlen;
int ihl; int ihl;
u8 nexthdr[2]; u8 nexthdr[2];
int padlen; int padlen, trimlen;
__wsum csumdiff;
if (!xo || (xo && !(xo->flags & CRYPTO_DONE))) if (!xo || (xo && !(xo->flags & CRYPTO_DONE)))
kfree(ESP_SKB_CB(skb)->tmp); kfree(ESP_SKB_CB(skb)->tmp);
...@@ -568,8 +569,15 @@ int esp_input_done2(struct sk_buff *skb, int err) ...@@ -568,8 +569,15 @@ int esp_input_done2(struct sk_buff *skb, int err)
skb->ip_summed = CHECKSUM_UNNECESSARY; skb->ip_summed = CHECKSUM_UNNECESSARY;
} }
pskb_trim(skb, skb->len - alen - padlen - 2); trimlen = alen + padlen + 2;
__skb_pull(skb, hlen); 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) if (x->props.mode == XFRM_MODE_TUNNEL)
skb_reset_transport_header(skb); skb_reset_transport_header(skb);
else else
......
...@@ -182,11 +182,13 @@ static struct sk_buff *esp4_gso_segment(struct sk_buff *skb, ...@@ -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) static int esp_input_tail(struct xfrm_state *x, struct sk_buff *skb)
{ {
struct crypto_aead *aead = x->data; 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))) if (!pskb_may_pull(skb, sizeof(struct ip_esp_hdr) + crypto_aead_ivsize(aead)))
return -EINVAL; return -EINVAL;
skb->ip_summed = CHECKSUM_NONE; if (!(xo->flags & CRYPTO_DONE))
skb->ip_summed = CHECKSUM_NONE;
return esp_input_done2(skb, 0); return esp_input_done2(skb, 0);
} }
...@@ -303,3 +305,4 @@ module_init(esp4_offload_init); ...@@ -303,3 +305,4 @@ module_init(esp4_offload_init);
module_exit(esp4_offload_exit); module_exit(esp4_offload_exit);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_AUTHOR("Steffen Klassert <steffen.klassert@secunet.com>"); MODULE_AUTHOR("Steffen Klassert <steffen.klassert@secunet.com>");
MODULE_ALIAS_XFRM_OFFLOAD_TYPE(AF_INET, XFRM_PROTO_ESP);
...@@ -20,7 +20,8 @@ ...@@ -20,7 +20,8 @@
static struct dst_entry *__xfrm4_dst_lookup(struct net *net, struct flowi4 *fl4, static struct dst_entry *__xfrm4_dst_lookup(struct net *net, struct flowi4 *fl4,
int tos, int oif, int tos, int oif,
const xfrm_address_t *saddr, const xfrm_address_t *saddr,
const xfrm_address_t *daddr) const xfrm_address_t *daddr,
u32 mark)
{ {
struct rtable *rt; struct rtable *rt;
...@@ -28,6 +29,7 @@ static struct dst_entry *__xfrm4_dst_lookup(struct net *net, struct flowi4 *fl4, ...@@ -28,6 +29,7 @@ static struct dst_entry *__xfrm4_dst_lookup(struct net *net, struct flowi4 *fl4,
fl4->daddr = daddr->a4; fl4->daddr = daddr->a4;
fl4->flowi4_tos = tos; fl4->flowi4_tos = tos;
fl4->flowi4_oif = l3mdev_master_ifindex_by_index(net, oif); fl4->flowi4_oif = l3mdev_master_ifindex_by_index(net, oif);
fl4->flowi4_mark = mark;
if (saddr) if (saddr)
fl4->saddr = saddr->a4; fl4->saddr = saddr->a4;
...@@ -42,20 +44,22 @@ static struct dst_entry *__xfrm4_dst_lookup(struct net *net, struct flowi4 *fl4, ...@@ -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, static struct dst_entry *xfrm4_dst_lookup(struct net *net, int tos, int oif,
const xfrm_address_t *saddr, const xfrm_address_t *saddr,
const xfrm_address_t *daddr) const xfrm_address_t *daddr,
u32 mark)
{ {
struct flowi4 fl4; 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, 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 dst_entry *dst;
struct flowi4 fl4; 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)) if (IS_ERR(dst))
return -EHOSTUNREACH; return -EHOSTUNREACH;
......
...@@ -470,7 +470,8 @@ int esp6_input_done2(struct sk_buff *skb, int err) ...@@ -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 hlen = sizeof(struct ip_esp_hdr) + crypto_aead_ivsize(aead);
int elen = skb->len - hlen; int elen = skb->len - hlen;
int hdr_len = skb_network_header_len(skb); int hdr_len = skb_network_header_len(skb);
int padlen; int padlen, trimlen;
__wsum csumdiff;
u8 nexthdr[2]; u8 nexthdr[2];
if (!xo || (xo && !(xo->flags & CRYPTO_DONE))) if (!xo || (xo && !(xo->flags & CRYPTO_DONE)))
...@@ -492,8 +493,17 @@ int esp6_input_done2(struct sk_buff *skb, int err) ...@@ -492,8 +493,17 @@ int esp6_input_done2(struct sk_buff *skb, int err)
/* ... check padding bits here. Silly. :-) */ /* ... check padding bits here. Silly. :-) */
pskb_trim(skb, skb->len - alen - padlen - 2); trimlen = alen + padlen + 2;
__skb_pull(skb, hlen); 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) if (x->props.mode == XFRM_MODE_TUNNEL)
skb_reset_transport_header(skb); skb_reset_transport_header(skb);
else else
......
...@@ -209,11 +209,13 @@ static struct sk_buff *esp6_gso_segment(struct sk_buff *skb, ...@@ -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) static int esp6_input_tail(struct xfrm_state *x, struct sk_buff *skb)
{ {
struct crypto_aead *aead = x->data; 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))) if (!pskb_may_pull(skb, sizeof(struct ip_esp_hdr) + crypto_aead_ivsize(aead)))
return -EINVAL; return -EINVAL;
skb->ip_summed = CHECKSUM_NONE; if (!(xo->flags & CRYPTO_DONE))
skb->ip_summed = CHECKSUM_NONE;
return esp6_input_done2(skb, 0); return esp6_input_done2(skb, 0);
} }
...@@ -332,3 +334,4 @@ module_init(esp6_offload_init); ...@@ -332,3 +334,4 @@ module_init(esp6_offload_init);
module_exit(esp6_offload_exit); module_exit(esp6_offload_exit);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_AUTHOR("Steffen Klassert <steffen.klassert@secunet.com>"); MODULE_AUTHOR("Steffen Klassert <steffen.klassert@secunet.com>");
MODULE_ALIAS_XFRM_OFFLOAD_TYPE(AF_INET6, XFRM_PROTO_ESP);
...@@ -34,6 +34,7 @@ EXPORT_SYMBOL(xfrm6_rcv_spi); ...@@ -34,6 +34,7 @@ EXPORT_SYMBOL(xfrm6_rcv_spi);
int xfrm6_transport_finish(struct sk_buff *skb, int async) int xfrm6_transport_finish(struct sk_buff *skb, int async)
{ {
struct xfrm_offload *xo = xfrm_offload(skb); struct xfrm_offload *xo = xfrm_offload(skb);
int nhlen = skb->data - skb_network_header(skb);
skb_network_header(skb)[IP6CB(skb)->nhoff] = skb_network_header(skb)[IP6CB(skb)->nhoff] =
XFRM_MODE_SKB_CB(skb)->protocol; XFRM_MODE_SKB_CB(skb)->protocol;
...@@ -43,8 +44,9 @@ int xfrm6_transport_finish(struct sk_buff *skb, int async) ...@@ -43,8 +44,9 @@ int xfrm6_transport_finish(struct sk_buff *skb, int async)
return 1; return 1;
#endif #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)); 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)) { if (xo && (xo->flags & XFRM_GRO)) {
skb_mac_header_rebuild(skb); skb_mac_header_rebuild(skb);
......
...@@ -27,7 +27,8 @@ ...@@ -27,7 +27,8 @@
static struct dst_entry *xfrm6_dst_lookup(struct net *net, int tos, int oif, static struct dst_entry *xfrm6_dst_lookup(struct net *net, int tos, int oif,
const xfrm_address_t *saddr, const xfrm_address_t *saddr,
const xfrm_address_t *daddr) const xfrm_address_t *daddr,
u32 mark)
{ {
struct flowi6 fl6; struct flowi6 fl6;
struct dst_entry *dst; struct dst_entry *dst;
...@@ -36,6 +37,7 @@ static struct dst_entry *xfrm6_dst_lookup(struct net *net, int tos, int oif, ...@@ -36,6 +37,7 @@ static struct dst_entry *xfrm6_dst_lookup(struct net *net, int tos, int oif,
memset(&fl6, 0, sizeof(fl6)); memset(&fl6, 0, sizeof(fl6));
fl6.flowi6_oif = l3mdev_master_ifindex_by_index(net, oif); fl6.flowi6_oif = l3mdev_master_ifindex_by_index(net, oif);
fl6.flowi6_flags = FLOWI_FLAG_SKIP_NH_OIF; fl6.flowi6_flags = FLOWI_FLAG_SKIP_NH_OIF;
fl6.flowi6_mark = mark;
memcpy(&fl6.daddr, daddr, sizeof(fl6.daddr)); memcpy(&fl6.daddr, daddr, sizeof(fl6.daddr));
if (saddr) if (saddr)
memcpy(&fl6.saddr, saddr, sizeof(fl6.saddr)); 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, ...@@ -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, 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 dst_entry *dst;
struct net_device *dev; 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)) if (IS_ERR(dst))
return -EHOSTUNREACH; return -EHOSTUNREACH;
......
...@@ -63,7 +63,7 @@ int xfrm_dev_state_add(struct net *net, struct xfrm_state *x, ...@@ -63,7 +63,7 @@ int xfrm_dev_state_add(struct net *net, struct xfrm_state *x,
xfrm_address_t *daddr; xfrm_address_t *daddr;
if (!x->type_offload) if (!x->type_offload)
return 0; return -EINVAL;
/* We don't yet support UDP encapsulation, TFC padding and ESN. */ /* We don't yet support UDP encapsulation, TFC padding and ESN. */
if (x->encap || x->tfcpad || (x->props.flags & XFRM_STATE_ESN)) 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, ...@@ -79,7 +79,8 @@ int xfrm_dev_state_add(struct net *net, struct xfrm_state *x,
daddr = &x->props.saddr; 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)) if (IS_ERR(dst))
return 0; return 0;
......
...@@ -424,6 +424,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) ...@@ -424,6 +424,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
nf_reset(skb); nf_reset(skb);
if (decaps) { if (decaps) {
skb->sp->olen = 0;
skb_dst_drop(skb); skb_dst_drop(skb);
gro_cells_receive(&gro_cells, skb); gro_cells_receive(&gro_cells, skb);
return 0; return 0;
...@@ -434,6 +435,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) ...@@ -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); err = x->inner_mode->afinfo->transport_finish(skb, xfrm_gro || async);
if (xfrm_gro) { if (xfrm_gro) {
skb->sp->olen = 0;
skb_dst_drop(skb); skb_dst_drop(skb);
gro_cells_receive(&gro_cells, skb); gro_cells_receive(&gro_cells, skb);
return err; return err;
......
...@@ -66,6 +66,9 @@ static int xfrm_output_one(struct sk_buff *skb, int err) ...@@ -66,6 +66,9 @@ static int xfrm_output_one(struct sk_buff *skb, int err)
goto error_nolock; goto error_nolock;
} }
if (x->props.output_mark)
skb->mark = x->props.output_mark;
err = x->outer_mode->output(x, skb); err = x->outer_mode->output(x, skb);
if (err) { if (err) {
XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEMODEERROR); XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEMODEERROR);
......
...@@ -122,7 +122,7 @@ static const struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short fa ...@@ -122,7 +122,7 @@ static const struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short fa
struct dst_entry *__xfrm_dst_lookup(struct net *net, int tos, int oif, struct dst_entry *__xfrm_dst_lookup(struct net *net, int tos, int oif,
const xfrm_address_t *saddr, const xfrm_address_t *saddr,
const xfrm_address_t *daddr, const xfrm_address_t *daddr,
int family) int family, u32 mark)
{ {
const struct xfrm_policy_afinfo *afinfo; const struct xfrm_policy_afinfo *afinfo;
struct dst_entry *dst; struct dst_entry *dst;
...@@ -131,7 +131,7 @@ struct dst_entry *__xfrm_dst_lookup(struct net *net, int tos, int oif, ...@@ -131,7 +131,7 @@ struct dst_entry *__xfrm_dst_lookup(struct net *net, int tos, int oif,
if (unlikely(afinfo == NULL)) if (unlikely(afinfo == NULL))
return ERR_PTR(-EAFNOSUPPORT); return ERR_PTR(-EAFNOSUPPORT);
dst = afinfo->dst_lookup(net, tos, oif, saddr, daddr); dst = afinfo->dst_lookup(net, tos, oif, saddr, daddr, mark);
rcu_read_unlock(); rcu_read_unlock();
...@@ -143,7 +143,7 @@ static inline struct dst_entry *xfrm_dst_lookup(struct xfrm_state *x, ...@@ -143,7 +143,7 @@ static inline struct dst_entry *xfrm_dst_lookup(struct xfrm_state *x,
int tos, int oif, int tos, int oif,
xfrm_address_t *prev_saddr, xfrm_address_t *prev_saddr,
xfrm_address_t *prev_daddr, xfrm_address_t *prev_daddr,
int family) int family, u32 mark)
{ {
struct net *net = xs_net(x); struct net *net = xs_net(x);
xfrm_address_t *saddr = &x->props.saddr; xfrm_address_t *saddr = &x->props.saddr;
...@@ -159,7 +159,7 @@ static inline struct dst_entry *xfrm_dst_lookup(struct xfrm_state *x, ...@@ -159,7 +159,7 @@ static inline struct dst_entry *xfrm_dst_lookup(struct xfrm_state *x,
daddr = x->coaddr; daddr = x->coaddr;
} }
dst = __xfrm_dst_lookup(net, tos, oif, saddr, daddr, family); dst = __xfrm_dst_lookup(net, tos, oif, saddr, daddr, family, mark);
if (!IS_ERR(dst)) { if (!IS_ERR(dst)) {
if (prev_saddr != saddr) if (prev_saddr != saddr)
...@@ -1340,14 +1340,14 @@ int __xfrm_sk_clone_policy(struct sock *sk, const struct sock *osk) ...@@ -1340,14 +1340,14 @@ int __xfrm_sk_clone_policy(struct sock *sk, const struct sock *osk)
static int static int
xfrm_get_saddr(struct net *net, int oif, xfrm_address_t *local, xfrm_get_saddr(struct net *net, int oif, xfrm_address_t *local,
xfrm_address_t *remote, unsigned short family) xfrm_address_t *remote, unsigned short family, u32 mark)
{ {
int err; int err;
const struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family); const struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family);
if (unlikely(afinfo == NULL)) if (unlikely(afinfo == NULL))
return -EINVAL; return -EINVAL;
err = afinfo->get_saddr(net, oif, local, remote); err = afinfo->get_saddr(net, oif, local, remote, mark);
rcu_read_unlock(); rcu_read_unlock();
return err; return err;
} }
...@@ -1378,7 +1378,7 @@ xfrm_tmpl_resolve_one(struct xfrm_policy *policy, const struct flowi *fl, ...@@ -1378,7 +1378,7 @@ xfrm_tmpl_resolve_one(struct xfrm_policy *policy, const struct flowi *fl,
if (xfrm_addr_any(local, tmpl->encap_family)) { if (xfrm_addr_any(local, tmpl->encap_family)) {
error = xfrm_get_saddr(net, fl->flowi_oif, error = xfrm_get_saddr(net, fl->flowi_oif,
&tmp, remote, &tmp, remote,
tmpl->encap_family); tmpl->encap_family, 0);
if (error) if (error)
goto fail; goto fail;
local = &tmp; local = &tmp;
...@@ -1598,7 +1598,8 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy, ...@@ -1598,7 +1598,8 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy,
if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) { if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) {
family = xfrm[i]->props.family; family = xfrm[i]->props.family;
dst = xfrm_dst_lookup(xfrm[i], tos, fl->flowi_oif, dst = xfrm_dst_lookup(xfrm[i], tos, fl->flowi_oif,
&saddr, &daddr, family); &saddr, &daddr, family,
xfrm[i]->props.output_mark);
err = PTR_ERR(dst); err = PTR_ERR(dst);
if (IS_ERR(dst)) if (IS_ERR(dst))
goto put_states; goto put_states;
......
...@@ -296,12 +296,14 @@ int xfrm_unregister_type_offload(const struct xfrm_type_offload *type, ...@@ -296,12 +296,14 @@ int xfrm_unregister_type_offload(const struct xfrm_type_offload *type,
} }
EXPORT_SYMBOL(xfrm_unregister_type_offload); EXPORT_SYMBOL(xfrm_unregister_type_offload);
static const struct xfrm_type_offload *xfrm_get_type_offload(u8 proto, unsigned short family) static const struct xfrm_type_offload *
xfrm_get_type_offload(u8 proto, unsigned short family, bool try_load)
{ {
struct xfrm_state_afinfo *afinfo; struct xfrm_state_afinfo *afinfo;
const struct xfrm_type_offload **typemap; const struct xfrm_type_offload **typemap;
const struct xfrm_type_offload *type; const struct xfrm_type_offload *type;
retry:
afinfo = xfrm_state_get_afinfo(family); afinfo = xfrm_state_get_afinfo(family);
if (unlikely(afinfo == NULL)) if (unlikely(afinfo == NULL))
return NULL; return NULL;
...@@ -311,6 +313,12 @@ static const struct xfrm_type_offload *xfrm_get_type_offload(u8 proto, unsigned ...@@ -311,6 +313,12 @@ static const struct xfrm_type_offload *xfrm_get_type_offload(u8 proto, unsigned
if ((type && !try_module_get(type->owner))) if ((type && !try_module_get(type->owner)))
type = NULL; type = NULL;
if (!type && try_load) {
request_module("xfrm-offload-%d-%d", family, proto);
try_load = 0;
goto retry;
}
rcu_read_unlock(); rcu_read_unlock();
return type; return type;
} }
...@@ -2165,7 +2173,7 @@ int xfrm_state_mtu(struct xfrm_state *x, int mtu) ...@@ -2165,7 +2173,7 @@ int xfrm_state_mtu(struct xfrm_state *x, int mtu)
return mtu - x->props.header_len; return mtu - x->props.header_len;
} }
int __xfrm_init_state(struct xfrm_state *x, bool init_replay) int __xfrm_init_state(struct xfrm_state *x, bool init_replay, bool offload)
{ {
struct xfrm_state_afinfo *afinfo; struct xfrm_state_afinfo *afinfo;
struct xfrm_mode *inner_mode; struct xfrm_mode *inner_mode;
...@@ -2230,7 +2238,7 @@ int __xfrm_init_state(struct xfrm_state *x, bool init_replay) ...@@ -2230,7 +2238,7 @@ int __xfrm_init_state(struct xfrm_state *x, bool init_replay)
if (x->type == NULL) if (x->type == NULL)
goto error; goto error;
x->type_offload = xfrm_get_type_offload(x->id.proto, family); x->type_offload = xfrm_get_type_offload(x->id.proto, family, offload);
err = x->type->init_state(x); err = x->type->init_state(x);
if (err) if (err)
...@@ -2258,7 +2266,7 @@ EXPORT_SYMBOL(__xfrm_init_state); ...@@ -2258,7 +2266,7 @@ EXPORT_SYMBOL(__xfrm_init_state);
int xfrm_init_state(struct xfrm_state *x) int xfrm_init_state(struct xfrm_state *x)
{ {
return __xfrm_init_state(x, true); return __xfrm_init_state(x, true, false);
} }
EXPORT_SYMBOL(xfrm_init_state); EXPORT_SYMBOL(xfrm_init_state);
......
...@@ -584,7 +584,10 @@ static struct xfrm_state *xfrm_state_construct(struct net *net, ...@@ -584,7 +584,10 @@ static struct xfrm_state *xfrm_state_construct(struct net *net,
xfrm_mark_get(attrs, &x->mark); xfrm_mark_get(attrs, &x->mark);
err = __xfrm_init_state(x, false); if (attrs[XFRMA_OUTPUT_MARK])
x->props.output_mark = nla_get_u32(attrs[XFRMA_OUTPUT_MARK]);
err = __xfrm_init_state(x, false, attrs[XFRMA_OFFLOAD_DEV]);
if (err) if (err)
goto error; goto error;
...@@ -899,6 +902,11 @@ static int copy_to_user_state_extra(struct xfrm_state *x, ...@@ -899,6 +902,11 @@ static int copy_to_user_state_extra(struct xfrm_state *x,
goto out; goto out;
if (x->security) if (x->security)
ret = copy_sec_ctx(x->security, skb); ret = copy_sec_ctx(x->security, skb);
if (x->props.output_mark) {
ret = nla_put_u32(skb, XFRMA_OUTPUT_MARK, x->props.output_mark);
if (ret)
goto out;
}
out: out:
return ret; return ret;
} }
...@@ -2454,6 +2462,7 @@ static const struct nla_policy xfrma_policy[XFRMA_MAX+1] = { ...@@ -2454,6 +2462,7 @@ static const struct nla_policy xfrma_policy[XFRMA_MAX+1] = {
[XFRMA_PROTO] = { .type = NLA_U8 }, [XFRMA_PROTO] = { .type = NLA_U8 },
[XFRMA_ADDRESS_FILTER] = { .len = sizeof(struct xfrm_address_filter) }, [XFRMA_ADDRESS_FILTER] = { .len = sizeof(struct xfrm_address_filter) },
[XFRMA_OFFLOAD_DEV] = { .len = sizeof(struct xfrm_user_offload) }, [XFRMA_OFFLOAD_DEV] = { .len = sizeof(struct xfrm_user_offload) },
[XFRMA_OUTPUT_MARK] = { .len = NLA_U32 },
}; };
static const struct nla_policy xfrma_spd_policy[XFRMA_SPD_MAX+1] = { static const struct nla_policy xfrma_spd_policy[XFRMA_SPD_MAX+1] = {
...@@ -2673,6 +2682,8 @@ static inline size_t xfrm_sa_len(struct xfrm_state *x) ...@@ -2673,6 +2682,8 @@ static inline size_t xfrm_sa_len(struct xfrm_state *x)
l += nla_total_size(sizeof(x->props.extra_flags)); l += nla_total_size(sizeof(x->props.extra_flags));
if (x->xso.dev) if (x->xso.dev)
l += nla_total_size(sizeof(x->xso)); l += nla_total_size(sizeof(x->xso));
if (x->props.output_mark)
l += nla_total_size(sizeof(x->props.output_mark));
/* Must count x->lastused as it may become non-zero behind our back. */ /* Must count x->lastused as it may become non-zero behind our back. */
l += nla_total_size_64bit(sizeof(u64)); l += nla_total_size_64bit(sizeof(u64));
......
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