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-02-16 1) Make struct xfrm_input_afinfo const, nothing writes to it. From Florian Westphal. 2) Remove all places that write to the afinfo policy backend and make the struct const then. From Florian Westphal. 3) Prepare for packet consuming gro callbacks and add ESP GRO handlers. ESP packets can be decapsulated at the GRO layer then. It saves a round through the stack for each ESP packet. Please note that this has a merge coflict between commit63fca65d08
("net: add confirm_neigh method to dst_ops") from net-next and3d7d25a68e
("xfrm: policy: remove garbage_collect callback")a2817d8b27
("xfrm: policy: remove family field") from ipsec-next. The conflict can be solved as it is done in linux-next. Please pull or let me know if there are problems. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
@@ -75,6 +75,19 @@ config INET6_ESP
|
||||
|
||||
If unsure, say Y.
|
||||
|
||||
config INET6_ESP_OFFLOAD
|
||||
tristate "IPv6: ESP transformation offload"
|
||||
depends on INET6_ESP
|
||||
select XFRM_OFFLOAD
|
||||
default n
|
||||
---help---
|
||||
Support for ESP transformation offload. This makes sense
|
||||
only if this system really does IPsec and want to do it
|
||||
with high throughput. A typical desktop system does not
|
||||
need it, even if it does IPsec.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config INET6_IPCOMP
|
||||
tristate "IPv6: IPComp transformation"
|
||||
select INET6_XFRM_TUNNEL
|
||||
|
@@ -30,6 +30,7 @@ ipv6-objs += $(ipv6-y)
|
||||
|
||||
obj-$(CONFIG_INET6_AH) += ah6.o
|
||||
obj-$(CONFIG_INET6_ESP) += esp6.o
|
||||
obj-$(CONFIG_INET6_ESP_OFFLOAD) += esp6_offload.o
|
||||
obj-$(CONFIG_INET6_IPCOMP) += ipcomp6.o
|
||||
obj-$(CONFIG_INET6_XFRM_TUNNEL) += xfrm6_tunnel.o
|
||||
obj-$(CONFIG_INET6_TUNNEL) += tunnel6.o
|
||||
|
108
net/ipv6/esp6_offload.c
Normal file
108
net/ipv6/esp6_offload.c
Normal file
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* IPV6 GSO/GRO offload support
|
||||
* Linux INET implementation
|
||||
*
|
||||
* Copyright (C) 2016 secunet Security Networks AG
|
||||
* Author: Steffen Klassert <steffen.klassert@secunet.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* ESP GRO support
|
||||
*/
|
||||
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/init.h>
|
||||
#include <net/protocol.h>
|
||||
#include <crypto/aead.h>
|
||||
#include <crypto/authenc.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/module.h>
|
||||
#include <net/ip.h>
|
||||
#include <net/xfrm.h>
|
||||
#include <net/esp.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <net/ip6_route.h>
|
||||
#include <net/ipv6.h>
|
||||
#include <linux/icmpv6.h>
|
||||
|
||||
static struct sk_buff **esp6_gro_receive(struct sk_buff **head,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
int offset = skb_gro_offset(skb);
|
||||
struct xfrm_offload *xo;
|
||||
struct xfrm_state *x;
|
||||
__be32 seq;
|
||||
__be32 spi;
|
||||
int err;
|
||||
|
||||
skb_pull(skb, offset);
|
||||
|
||||
if ((err = xfrm_parse_spi(skb, IPPROTO_ESP, &spi, &seq)) != 0)
|
||||
goto out;
|
||||
|
||||
err = secpath_set(skb);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
if (skb->sp->len == XFRM_MAX_DEPTH)
|
||||
goto out;
|
||||
|
||||
x = xfrm_state_lookup(dev_net(skb->dev), skb->mark,
|
||||
(xfrm_address_t *)&ipv6_hdr(skb)->daddr,
|
||||
spi, IPPROTO_ESP, AF_INET6);
|
||||
if (!x)
|
||||
goto out;
|
||||
|
||||
skb->sp->xvec[skb->sp->len++] = x;
|
||||
skb->sp->olen++;
|
||||
|
||||
xo = xfrm_offload(skb);
|
||||
if (!xo) {
|
||||
xfrm_state_put(x);
|
||||
goto out;
|
||||
}
|
||||
xo->flags |= XFRM_GRO;
|
||||
|
||||
XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6 = NULL;
|
||||
XFRM_SPI_SKB_CB(skb)->family = AF_INET6;
|
||||
XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct ipv6hdr, daddr);
|
||||
XFRM_SPI_SKB_CB(skb)->seq = seq;
|
||||
|
||||
/* We don't need to handle errors from xfrm_input, it does all
|
||||
* the error handling and frees the resources on error. */
|
||||
xfrm_input(skb, IPPROTO_ESP, spi, -2);
|
||||
|
||||
return ERR_PTR(-EINPROGRESS);
|
||||
out:
|
||||
skb_push(skb, offset);
|
||||
NAPI_GRO_CB(skb)->same_flow = 0;
|
||||
NAPI_GRO_CB(skb)->flush = 1;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const struct net_offload esp6_offload = {
|
||||
.callbacks = {
|
||||
.gro_receive = esp6_gro_receive,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init esp6_offload_init(void)
|
||||
{
|
||||
return inet6_add_offload(&esp6_offload, IPPROTO_ESP);
|
||||
}
|
||||
|
||||
static void __exit esp6_offload_exit(void)
|
||||
{
|
||||
inet6_del_offload(&esp6_offload, IPPROTO_ESP);
|
||||
}
|
||||
|
||||
module_init(esp6_offload_init);
|
||||
module_exit(esp6_offload_exit);
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Steffen Klassert <steffen.klassert@secunet.com>");
|
@@ -253,7 +253,7 @@ out_unlock:
|
||||
rcu_read_unlock();
|
||||
|
||||
out:
|
||||
NAPI_GRO_CB(skb)->flush |= flush;
|
||||
skb_gro_flush_final(skb, pp, flush);
|
||||
|
||||
return pp;
|
||||
}
|
||||
|
@@ -33,6 +33,8 @@ EXPORT_SYMBOL(xfrm6_rcv_spi);
|
||||
|
||||
int xfrm6_transport_finish(struct sk_buff *skb, int async)
|
||||
{
|
||||
struct xfrm_offload *xo = xfrm_offload(skb);
|
||||
|
||||
skb_network_header(skb)[IP6CB(skb)->nhoff] =
|
||||
XFRM_MODE_SKB_CB(skb)->protocol;
|
||||
|
||||
@@ -44,6 +46,11 @@ int xfrm6_transport_finish(struct sk_buff *skb, int async)
|
||||
ipv6_hdr(skb)->payload_len = htons(skb->len);
|
||||
__skb_push(skb, skb->data - skb_network_header(skb));
|
||||
|
||||
if (xo && (xo->flags & XFRM_GRO)) {
|
||||
skb_mac_header_rebuild(skb);
|
||||
return -1;
|
||||
}
|
||||
|
||||
NF_HOOK(NFPROTO_IPV6, NF_INET_PRE_ROUTING,
|
||||
dev_net(skb->dev), NULL, skb, skb->dev, NULL,
|
||||
ip6_rcv_finish);
|
||||
@@ -69,18 +76,9 @@ int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr,
|
||||
struct xfrm_state *x = NULL;
|
||||
int i = 0;
|
||||
|
||||
/* Allocate new secpath or COW existing one. */
|
||||
if (!skb->sp || atomic_read(&skb->sp->refcnt) != 1) {
|
||||
struct sec_path *sp;
|
||||
|
||||
sp = secpath_dup(skb->sp);
|
||||
if (!sp) {
|
||||
XFRM_INC_STATS(net, LINUX_MIB_XFRMINERROR);
|
||||
goto drop;
|
||||
}
|
||||
if (skb->sp)
|
||||
secpath_put(skb->sp);
|
||||
skb->sp = sp;
|
||||
if (secpath_set(skb)) {
|
||||
XFRM_INC_STATS(net, LINUX_MIB_XFRMINERROR);
|
||||
goto drop;
|
||||
}
|
||||
|
||||
if (1 + skb->sp->len == XFRM_MAX_DEPTH) {
|
||||
|
@@ -47,6 +47,7 @@ static int xfrm6_transport_output(struct xfrm_state *x, struct sk_buff *skb)
|
||||
static int xfrm6_transport_input(struct xfrm_state *x, struct sk_buff *skb)
|
||||
{
|
||||
int ihl = skb->data - skb_transport_header(skb);
|
||||
struct xfrm_offload *xo = xfrm_offload(skb);
|
||||
|
||||
if (skb->transport_header != skb->network_header) {
|
||||
memmove(skb_transport_header(skb),
|
||||
@@ -55,7 +56,8 @@ static int xfrm6_transport_input(struct xfrm_state *x, struct sk_buff *skb)
|
||||
}
|
||||
ipv6_hdr(skb)->payload_len = htons(skb->len + ihl -
|
||||
sizeof(struct ipv6hdr));
|
||||
skb_reset_transport_header(skb);
|
||||
if (!xo || !(xo->flags & XFRM_GRO))
|
||||
skb_reset_transport_header(skb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@@ -25,8 +25,6 @@
|
||||
#include <net/mip6.h>
|
||||
#endif
|
||||
|
||||
static struct xfrm_policy_afinfo xfrm6_policy_afinfo;
|
||||
|
||||
static struct dst_entry *xfrm6_dst_lookup(struct net *net, int tos, int oif,
|
||||
const xfrm_address_t *saddr,
|
||||
const xfrm_address_t *daddr)
|
||||
@@ -220,7 +218,7 @@ static inline int xfrm6_garbage_collect(struct dst_ops *ops)
|
||||
{
|
||||
struct net *net = container_of(ops, struct net, xfrm.xfrm6_dst_ops);
|
||||
|
||||
xfrm6_policy_afinfo.garbage_collect(net);
|
||||
xfrm_garbage_collect_deferred(net);
|
||||
return dst_entries_get_fast(ops) > ops->gc_thresh * 2;
|
||||
}
|
||||
|
||||
@@ -291,8 +289,7 @@ static struct dst_ops xfrm6_dst_ops_template = {
|
||||
.gc_thresh = INT_MAX,
|
||||
};
|
||||
|
||||
static struct xfrm_policy_afinfo xfrm6_policy_afinfo = {
|
||||
.family = AF_INET6,
|
||||
static const struct xfrm_policy_afinfo xfrm6_policy_afinfo = {
|
||||
.dst_ops = &xfrm6_dst_ops_template,
|
||||
.dst_lookup = xfrm6_dst_lookup,
|
||||
.get_saddr = xfrm6_get_saddr,
|
||||
@@ -305,7 +302,7 @@ static struct xfrm_policy_afinfo xfrm6_policy_afinfo = {
|
||||
|
||||
static int __init xfrm6_policy_init(void)
|
||||
{
|
||||
return xfrm_policy_register_afinfo(&xfrm6_policy_afinfo);
|
||||
return xfrm_policy_register_afinfo(&xfrm6_policy_afinfo, AF_INET6);
|
||||
}
|
||||
|
||||
static void xfrm6_policy_fini(void)
|
||||
|
@@ -162,9 +162,8 @@ static const struct inet6_protocol ipcomp6_protocol = {
|
||||
.flags = INET6_PROTO_NOPOLICY,
|
||||
};
|
||||
|
||||
static struct xfrm_input_afinfo xfrm6_input_afinfo = {
|
||||
static const struct xfrm_input_afinfo xfrm6_input_afinfo = {
|
||||
.family = AF_INET6,
|
||||
.owner = THIS_MODULE,
|
||||
.callback = xfrm6_rcv_cb,
|
||||
};
|
||||
|
||||
|
Reference in New Issue
Block a user