Hello.
I've created POC code to perform asynchronous IPsec [ESP]
processing. Please comment about bugs in the following patch.
It of course very dirty - but it is only begining,
I just want to know if approach is right.
Patch was tested with several ssh session and some
traffic like find / and tcpdump over them.
Thank you.
diff -ru ../linux-2.6-orig/net/ipv4/esp4.c ./net/ipv4/esp4.c
--- ../linux-2.6-orig/net/ipv4/esp4.c 2005-04-25 15:41:39.000000000 +0400
+++ ./net/ipv4/esp4.c 2005-04-29 14:34:10.000000000 +0400
@@ -7,6 +7,7 @@
#include <linux/crypto.h>
#include <linux/pfkeyv2.h>
#include <linux/random.h>
+#include <linux/timer.h>
#include <net/icmp.h>
#include <net/udp.h>
@@ -17,6 +18,95 @@
__u8 proto;
};
+static int esp_output(struct xfrm_state *x, struct sk_buff *skb);
+
+struct esp_async {
+ struct timer_list tm;
+ struct sk_buff *skb;
+ struct xfrm_state *x;
+ struct dst_entry *dst;
+};
+
+static void esp4_callback(unsigned long data)
+{
+ struct esp_async *ea = (struct esp_async *)data;
+ struct sk_buff *skb = ea->skb;
+ struct dst_entry *dst = ea->dst;
+ struct xfrm_state *x = ea->x;
+ int err;
+
+ printk("%s: skb=%p, skb->users=%d.\n", __func__, skb,
atomic_read(&skb->users));
+ printk("%s: dst=%p, skb->dst=%p.\n", __func__, dst, skb->dst);
+ printk("%s: xfrm=%p, skb->dst->xfrm=%p.\n", __func__, x,
(skb->dst)?skb->dst->xfrm:NULL);
+
+ spin_lock_bh(&x->lock);
+ err = esp_output(x, skb);
+ spin_unlock_bh(&x->lock);
+
+ printk("%s: Data has been processed: err=%d.\n", __func__, err);
+
+ if (err)
+ goto err_out;
+
+ skb->dst = dst_pop(dst);
+ printk("%s: pop has been finished: skb->dst=%p, dst=%p,
skb->users=%d.\n",
+ __func__, skb->dst, dst, atomic_read(&skb->users));
+ if (!skb->dst)
+ goto err_out;
+
+ dst_output(skb);
+
+out:
+ kfree(ea);
+ return;
+
+err_out:
+ kfree_skb(skb);
+ goto out;
+}
+
+static int esp_output_async(struct xfrm_state *x, struct sk_buff *skb)
+{
+ struct esp_async *ea;
+ struct dst_entry *child;
+
+ printk("%s: enter. Child list: ", __func__);
+ for (child = skb->dst; child; child = child->child)
+ printk("%p [%s] [%d] -> ", child, child->dev->name,
atomic_read(&child->__refcnt));
+ printk("\n");
+
+ ea = kmalloc(sizeof(*ea), GFP_ATOMIC);
+ if (!ea)
+ return -ENOMEM;
+
+ memset(ea, 0, sizeof(*ea));
+
+ skb = skb_clone(skb, GFP_ATOMIC);
+ if (!skb)
+ return -ENOMEM;
+ dst_hold(skb->dst);
+
+ ea->skb = skb;
+ ea->x = x;
+ ea->dst = skb->dst;
+
+ printk("%s: x=%p, skb=%p, skb->dst=%p, skb->dst->xfrm=%p.\n",
+ __func__, x, skb, skb->dst, skb->dst->xfrm);
+
+ init_timer(&ea->tm);
+ ea->tm.function = &esp4_callback;
+ ea->tm.data = (unsigned long)ea;
+ ea->tm.expires = jiffies;
+
+ add_timer(&ea->tm);
+
+ printk("%s: timer added: skb->users=%d.\n", __func__,
atomic_read(&skb->users));
+
+ return 0;
+
+}
+
+
static int esp_output(struct xfrm_state *x, struct sk_buff *skb)
{
int err;
@@ -465,7 +555,7 @@
.get_max_size = esp4_get_max_size,
.input = esp_input,
.post_input = esp_post_input,
- .output = esp_output
+ .output = esp_output_async
};
static struct net_protocol esp4_protocol = {
diff -ru ../linux-2.6-orig/net/ipv4/xfrm4_output.c ./net/ipv4/xfrm4_output.c
--- ../linux-2.6-orig/net/ipv4/xfrm4_output.c 2005-04-25 15:41:40.000000000
+0400
+++ ./net/ipv4/xfrm4_output.c 2005-04-29 12:13:41.000000000 +0400
@@ -124,12 +124,6 @@
x->curlft.packets++;
spin_unlock_bh(&x->lock);
-
- if (!(skb->dst = dst_pop(dst))) {
- err = -EHOSTUNREACH;
- goto error_nolock;
- }
- err = NET_XMIT_BYPASS;
out_exit:
return err;
--
Evgeniy Polyakov
|