|
@@ -8,15 +8,29 @@
|
|
*
|
|
*
|
|
*/
|
|
*/
|
|
|
|
|
|
|
|
+#include <linux/bottom_half.h>
|
|
|
|
+#include <linux/interrupt.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/module.h>
|
|
#include <linux/module.h>
|
|
#include <linux/netdevice.h>
|
|
#include <linux/netdevice.h>
|
|
|
|
+#include <linux/percpu.h>
|
|
#include <net/dst.h>
|
|
#include <net/dst.h>
|
|
#include <net/ip.h>
|
|
#include <net/ip.h>
|
|
#include <net/xfrm.h>
|
|
#include <net/xfrm.h>
|
|
#include <net/ip_tunnels.h>
|
|
#include <net/ip_tunnels.h>
|
|
#include <net/ip6_tunnel.h>
|
|
#include <net/ip6_tunnel.h>
|
|
|
|
|
|
|
|
+struct xfrm_trans_tasklet {
|
|
|
|
+ struct tasklet_struct tasklet;
|
|
|
|
+ struct sk_buff_head queue;
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+struct xfrm_trans_cb {
|
|
|
|
+ int (*finish)(struct net *net, struct sock *sk, struct sk_buff *skb);
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+#define XFRM_TRANS_SKB_CB(__skb) ((struct xfrm_trans_cb *)&((__skb)->cb[0]))
|
|
|
|
+
|
|
static struct kmem_cache *secpath_cachep __read_mostly;
|
|
static struct kmem_cache *secpath_cachep __read_mostly;
|
|
|
|
|
|
static DEFINE_SPINLOCK(xfrm_input_afinfo_lock);
|
|
static DEFINE_SPINLOCK(xfrm_input_afinfo_lock);
|
|
@@ -25,6 +39,8 @@ static struct xfrm_input_afinfo const __rcu *xfrm_input_afinfo[AF_INET6 + 1];
|
|
static struct gro_cells gro_cells;
|
|
static struct gro_cells gro_cells;
|
|
static struct net_device xfrm_napi_dev;
|
|
static struct net_device xfrm_napi_dev;
|
|
|
|
|
|
|
|
+static DEFINE_PER_CPU(struct xfrm_trans_tasklet, xfrm_trans_tasklet);
|
|
|
|
+
|
|
int xfrm_input_register_afinfo(const struct xfrm_input_afinfo *afinfo)
|
|
int xfrm_input_register_afinfo(const struct xfrm_input_afinfo *afinfo)
|
|
{
|
|
{
|
|
int err = 0;
|
|
int err = 0;
|
|
@@ -477,9 +493,41 @@ int xfrm_input_resume(struct sk_buff *skb, int nexthdr)
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(xfrm_input_resume);
|
|
EXPORT_SYMBOL(xfrm_input_resume);
|
|
|
|
|
|
|
|
+static void xfrm_trans_reinject(unsigned long data)
|
|
|
|
+{
|
|
|
|
+ struct xfrm_trans_tasklet *trans = (void *)data;
|
|
|
|
+ struct sk_buff_head queue;
|
|
|
|
+ struct sk_buff *skb;
|
|
|
|
+
|
|
|
|
+ __skb_queue_head_init(&queue);
|
|
|
|
+ skb_queue_splice_init(&trans->queue, &queue);
|
|
|
|
+
|
|
|
|
+ while ((skb = __skb_dequeue(&queue)))
|
|
|
|
+ XFRM_TRANS_SKB_CB(skb)->finish(dev_net(skb->dev), NULL, skb);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+int xfrm_trans_queue(struct sk_buff *skb,
|
|
|
|
+ int (*finish)(struct net *, struct sock *,
|
|
|
|
+ struct sk_buff *))
|
|
|
|
+{
|
|
|
|
+ struct xfrm_trans_tasklet *trans;
|
|
|
|
+
|
|
|
|
+ trans = this_cpu_ptr(&xfrm_trans_tasklet);
|
|
|
|
+
|
|
|
|
+ if (skb_queue_len(&trans->queue) >= netdev_max_backlog)
|
|
|
|
+ return -ENOBUFS;
|
|
|
|
+
|
|
|
|
+ XFRM_TRANS_SKB_CB(skb)->finish = finish;
|
|
|
|
+ skb_queue_tail(&trans->queue, skb);
|
|
|
|
+ tasklet_schedule(&trans->tasklet);
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+EXPORT_SYMBOL(xfrm_trans_queue);
|
|
|
|
+
|
|
void __init xfrm_input_init(void)
|
|
void __init xfrm_input_init(void)
|
|
{
|
|
{
|
|
int err;
|
|
int err;
|
|
|
|
+ int i;
|
|
|
|
|
|
init_dummy_netdev(&xfrm_napi_dev);
|
|
init_dummy_netdev(&xfrm_napi_dev);
|
|
err = gro_cells_init(&gro_cells, &xfrm_napi_dev);
|
|
err = gro_cells_init(&gro_cells, &xfrm_napi_dev);
|
|
@@ -490,4 +538,13 @@ void __init xfrm_input_init(void)
|
|
sizeof(struct sec_path),
|
|
sizeof(struct sec_path),
|
|
0, SLAB_HWCACHE_ALIGN|SLAB_PANIC,
|
|
0, SLAB_HWCACHE_ALIGN|SLAB_PANIC,
|
|
NULL);
|
|
NULL);
|
|
|
|
+
|
|
|
|
+ for_each_possible_cpu(i) {
|
|
|
|
+ struct xfrm_trans_tasklet *trans;
|
|
|
|
+
|
|
|
|
+ trans = &per_cpu(xfrm_trans_tasklet, i);
|
|
|
|
+ __skb_queue_head_init(&trans->queue);
|
|
|
|
+ tasklet_init(&trans->tasklet, xfrm_trans_reinject,
|
|
|
|
+ (unsigned long)trans);
|
|
|
|
+ }
|
|
}
|
|
}
|