[IPSEC]: Merge most of the output path
authorHerbert Xu <herbert@gondor.apana.org.au>
Wed, 14 Nov 2007 05:43:11 +0000 (21:43 -0800)
committerDavid S. Miller <davem@davemloft.net>
Mon, 28 Jan 2008 22:53:48 +0000 (14:53 -0800)
As part of the work on asynchrnous cryptographic operations, we need
to be able to resume from the spot where they occur.  As such, it
helps if we isolate them to one spot.

This patch moves most of the remaining family-specific processing into
the common output code.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/dst.h
include/net/xfrm.h
net/ipv4/route.c
net/ipv4/xfrm4_output.c
net/ipv4/xfrm4_policy.c
net/ipv4/xfrm4_state.c
net/ipv6/route.c
net/ipv6/xfrm6_output.c
net/ipv6/xfrm6_policy.c
net/ipv6/xfrm6_state.c
net/xfrm/xfrm_output.c

index 7a0b1bde8e28387663b3e22ff1e73855f3a7d199..e86b9a008ebf300ec118c2fd909f05eca1c10e11 100644 (file)
@@ -98,6 +98,7 @@ struct dst_ops
        struct dst_entry *      (*negative_advice)(struct dst_entry *);
        void                    (*link_failure)(struct sk_buff *);
        void                    (*update_pmtu)(struct dst_entry *dst, u32 mtu);
+       int                     (*local_out)(struct sk_buff *skb);
        int                     entry_size;
 
        atomic_t                entries;
index a9dbe091ae58f9081bcdca5b11d29a7fb9951b12..ab9e747340b4433a2ebc17df2a93354878d2163f 100644 (file)
@@ -259,6 +259,7 @@ struct xfrm_state_afinfo {
        unsigned int            family;
        unsigned int            proto;
        unsigned int            eth_proto;
+       unsigned int            nf_post_routing;
        struct module           *owner;
        struct xfrm_type        *type_map[IPPROTO_MAX];
        struct xfrm_mode        *mode_map[XFRM_MODE_MAX];
index 137b8eb666b780d8718624b078fb1ae3270d8412..94ef788a2ac65f29cdc78210ff197087bc4d9d9b 100644 (file)
@@ -166,6 +166,7 @@ static struct dst_ops ipv4_dst_ops = {
        .negative_advice =      ipv4_negative_advice,
        .link_failure =         ipv4_link_failure,
        .update_pmtu =          ip_rt_update_pmtu,
+       .local_out =            ip_local_out,
        .entry_size =           sizeof(struct rtable),
 };
 
index 0ffc3d07848942b78eb41025a175876d81b4fbe5..2fb4efa3ff2cf74cdd815d27ccf24fa51b98b417 100644 (file)
@@ -59,7 +59,7 @@ int xfrm4_prepare_output(struct xfrm_state *x, struct sk_buff *skb)
                return err;
 
        memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
-       IPCB(skb)->flags |= IPSKB_XFRM_TUNNEL_SIZE;
+       IPCB(skb)->flags |= IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED;
 
        skb->protocol = htons(ETH_P_IP);
 
@@ -67,87 +67,19 @@ int xfrm4_prepare_output(struct xfrm_state *x, struct sk_buff *skb)
 }
 EXPORT_SYMBOL(xfrm4_prepare_output);
 
-static inline int xfrm4_output_one(struct sk_buff *skb)
-{
-       int err;
-
-       err = xfrm_output(skb);
-       if (err)
-               goto error_nolock;
-
-       IPCB(skb)->flags |= IPSKB_XFRM_TRANSFORMED;
-       err = 0;
-
-out_exit:
-       return err;
-error_nolock:
-       kfree_skb(skb);
-       goto out_exit;
-}
-
-static int xfrm4_output_finish2(struct sk_buff *skb)
-{
-       int err;
-
-       while (likely((err = xfrm4_output_one(skb)) == 0)) {
-               nf_reset(skb);
-
-               err = __ip_local_out(skb);
-               if (unlikely(err != 1))
-                       break;
-
-               if (!skb->dst->xfrm)
-                       return dst_output(skb);
-
-               err = nf_hook(PF_INET, NF_IP_POST_ROUTING, skb, NULL,
-                             skb->dst->dev, xfrm4_output_finish2);
-               if (unlikely(err != 1))
-                       break;
-       }
-
-       return err;
-}
-
 static int xfrm4_output_finish(struct sk_buff *skb)
 {
-       struct sk_buff *segs;
-
 #ifdef CONFIG_NETFILTER
        if (!skb->dst->xfrm) {
                IPCB(skb)->flags |= IPSKB_REROUTED;
                return dst_output(skb);
        }
-#endif
 
-       if (!skb_is_gso(skb))
-               return xfrm4_output_finish2(skb);
+       IPCB(skb)->flags |= IPSKB_XFRM_TRANSFORMED;
+#endif
 
        skb->protocol = htons(ETH_P_IP);
-       segs = skb_gso_segment(skb, 0);
-       kfree_skb(skb);
-       if (unlikely(IS_ERR(segs)))
-               return PTR_ERR(segs);
-
-       do {
-               struct sk_buff *nskb = segs->next;
-               int err;
-
-               segs->next = NULL;
-               err = xfrm4_output_finish2(segs);
-
-               if (unlikely(err)) {
-                       while ((segs = nskb)) {
-                               nskb = segs->next;
-                               segs->next = NULL;
-                               kfree_skb(segs);
-                       }
-                       return err;
-               }
-
-               segs = nskb;
-       } while (segs);
-
-       return 0;
+       return xfrm_output(skb);
 }
 
 int xfrm4_output(struct sk_buff *skb)
index 1d7524375b49a29f7b9faad71bb94eed743e9692..b4948c170b3ea37ac4c41a17901bdd4ff9ba2f35 100644 (file)
@@ -237,6 +237,7 @@ static struct dst_ops xfrm4_dst_ops = {
        .update_pmtu =          xfrm4_update_pmtu,
        .destroy =              xfrm4_dst_destroy,
        .ifdown =               xfrm4_dst_ifdown,
+       .local_out =            __ip_local_out,
        .gc_thresh =            1024,
        .entry_size =           sizeof(struct xfrm_dst),
 };
index 85f04b7b237f628eed2cfa54cd3690294eed948c..80292fbf221a967a7ea931192e3af5d0dc8d641a 100644 (file)
@@ -11,6 +11,7 @@
 #include <net/xfrm.h>
 #include <linux/pfkeyv2.h>
 #include <linux/ipsec.h>
+#include <linux/netfilter_ipv4.h>
 
 static struct xfrm_state_afinfo xfrm4_state_afinfo;
 
@@ -66,6 +67,7 @@ static struct xfrm_state_afinfo xfrm4_state_afinfo = {
        .family                 = AF_INET,
        .proto                  = IPPROTO_IPIP,
        .eth_proto              = htons(ETH_P_IP),
+       .nf_post_routing        = NF_IP_POST_ROUTING,
        .owner                  = THIS_MODULE,
        .init_flags             = xfrm4_init_flags,
        .init_tempsel           = __xfrm4_init_tempsel,
index ac70e2d3b10c76bb0a1a21cc1f39127d63d56642..4ef2cfaa3467d28d4e9d4bfb3b29c1938055e2d1 100644 (file)
@@ -113,6 +113,7 @@ static struct dst_ops ip6_dst_ops = {
        .negative_advice        =       ip6_negative_advice,
        .link_failure           =       ip6_link_failure,
        .update_pmtu            =       ip6_rt_update_pmtu,
+       .local_out              =       ip6_local_out,
        .entry_size             =       sizeof(struct rt6_info),
 };
 
index 0f0ff51f6dbadcb5119f5cd15d16a4ab32ac45c4..a0a924991c4f5db8e023832bd5a126e4d4856b22 100644 (file)
@@ -66,6 +66,9 @@ int xfrm6_prepare_output(struct xfrm_state *x, struct sk_buff *skb)
                return err;
 
        memset(IP6CB(skb), 0, sizeof(*IP6CB(skb)));
+#ifdef CONFIG_NETFILTER
+       IP6CB(skb)->flags |= IP6SKB_XFRM_TRANSFORMED;
+#endif
 
        skb->protocol = htons(ETH_P_IPV6);
 
@@ -73,80 +76,14 @@ int xfrm6_prepare_output(struct xfrm_state *x, struct sk_buff *skb)
 }
 EXPORT_SYMBOL(xfrm6_prepare_output);
 
-static inline int xfrm6_output_one(struct sk_buff *skb)
-{
-       int err;
-
-       err = xfrm_output(skb);
-       if (err)
-               goto error_nolock;
-
-       IP6CB(skb)->flags |= IP6SKB_XFRM_TRANSFORMED;
-       err = 0;
-
-out_exit:
-       return err;
-error_nolock:
-       kfree_skb(skb);
-       goto out_exit;
-}
-
-static int xfrm6_output_finish2(struct sk_buff *skb)
-{
-       int err;
-
-       while (likely((err = xfrm6_output_one(skb)) == 0)) {
-               nf_reset(skb);
-
-               err = __ip6_local_out(skb);
-               if (unlikely(err != 1))
-                       break;
-
-               if (!skb->dst->xfrm)
-                       return dst_output(skb);
-
-               err = nf_hook(PF_INET6, NF_IP6_POST_ROUTING, skb, NULL,
-                             skb->dst->dev, xfrm6_output_finish2);
-               if (unlikely(err != 1))
-                       break;
-       }
-
-       return err;
-}
-
 static int xfrm6_output_finish(struct sk_buff *skb)
 {
-       struct sk_buff *segs;
-
-       if (!skb_is_gso(skb))
-               return xfrm6_output_finish2(skb);
+#ifdef CONFIG_NETFILTER
+       IP6CB(skb)->flags |= IP6SKB_XFRM_TRANSFORMED;
+#endif
 
        skb->protocol = htons(ETH_P_IPV6);
-       segs = skb_gso_segment(skb, 0);
-       kfree_skb(skb);
-       if (unlikely(IS_ERR(segs)))
-               return PTR_ERR(segs);
-
-       do {
-               struct sk_buff *nskb = segs->next;
-               int err;
-
-               segs->next = NULL;
-               err = xfrm6_output_finish2(segs);
-
-               if (unlikely(err)) {
-                       while ((segs = nskb)) {
-                               nskb = segs->next;
-                               segs->next = NULL;
-                               kfree_skb(segs);
-                       }
-                       return err;
-               }
-
-               segs = nskb;
-       } while (segs);
-
-       return 0;
+       return xfrm_output(skb);
 }
 
 int xfrm6_output(struct sk_buff *skb)
index 63932c5fd3c71072028e49333e103b8d9abb57d6..a31dd531e191802dab91330293322202169f5856 100644 (file)
@@ -252,6 +252,7 @@ static struct dst_ops xfrm6_dst_ops = {
        .update_pmtu =          xfrm6_update_pmtu,
        .destroy =              xfrm6_dst_destroy,
        .ifdown =               xfrm6_dst_ifdown,
+       .local_out =            __ip6_local_out,
        .gc_thresh =            1024,
        .entry_size =           sizeof(struct xfrm_dst),
 };
index 90fef0a4726fb449a540b8f3e951900edeaf288a..bb09e85a336dd53fdad0b7d4522c36c9272b9120 100644 (file)
@@ -14,6 +14,7 @@
 #include <net/xfrm.h>
 #include <linux/pfkeyv2.h>
 #include <linux/ipsec.h>
+#include <linux/netfilter_ipv6.h>
 #include <net/dsfield.h>
 #include <net/ipv6.h>
 #include <net/addrconf.h>
@@ -189,6 +190,7 @@ static struct xfrm_state_afinfo xfrm6_state_afinfo = {
        .family                 = AF_INET6,
        .proto                  = IPPROTO_IPV6,
        .eth_proto              = htons(ETH_P_IPV6),
+       .nf_post_routing        = NF_IP6_POST_ROUTING,
        .owner                  = THIS_MODULE,
        .init_tempsel           = __xfrm6_init_tempsel,
        .tmpl_sort              = __xfrm6_tmpl_sort,
index b1efdc8850a7413b39aed94b51301a0a85180b9f..bcb3701c5cf3e27d34e3fdd37203e2fc3a79bdd1 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/errno.h>
 #include <linux/module.h>
 #include <linux/netdevice.h>
+#include <linux/netfilter.h>
 #include <linux/skbuff.h>
 #include <linux/spinlock.h>
 #include <net/dst.h>
@@ -40,7 +41,7 @@ err:
        return err;
 }
 
-int xfrm_output(struct sk_buff *skb)
+static int xfrm_output_one(struct sk_buff *skb)
 {
        struct dst_entry *dst = skb->dst;
        struct xfrm_state *x = dst->xfrm;
@@ -87,10 +88,73 @@ int xfrm_output(struct sk_buff *skb)
 
        err = 0;
 
-error_nolock:
+out_exit:
        return err;
 error:
        spin_unlock_bh(&x->lock);
-       goto error_nolock;
+error_nolock:
+       kfree_skb(skb);
+       goto out_exit;
+}
+
+static int xfrm_output2(struct sk_buff *skb)
+{
+       int err;
+
+       while (likely((err = xfrm_output_one(skb)) == 0)) {
+               struct xfrm_state *x;
+
+               nf_reset(skb);
+
+               err = skb->dst->ops->local_out(skb);
+               if (unlikely(err != 1))
+                       break;
+
+               x = skb->dst->xfrm;
+               if (!x)
+                       return dst_output(skb);
+
+               err = nf_hook(x->inner_mode->afinfo->family,
+                             x->inner_mode->afinfo->nf_post_routing, skb,
+                             NULL, skb->dst->dev, xfrm_output2);
+               if (unlikely(err != 1))
+                       break;
+       }
+
+       return err;
+}
+
+int xfrm_output(struct sk_buff *skb)
+{
+       struct sk_buff *segs;
+
+       if (!skb_is_gso(skb))
+               return xfrm_output2(skb);
+
+       segs = skb_gso_segment(skb, 0);
+       kfree_skb(skb);
+       if (unlikely(IS_ERR(segs)))
+               return PTR_ERR(segs);
+
+       do {
+               struct sk_buff *nskb = segs->next;
+               int err;
+
+               segs->next = NULL;
+               err = xfrm_output2(segs);
+
+               if (unlikely(err)) {
+                       while ((segs = nskb)) {
+                               nskb = segs->next;
+                               segs->next = NULL;
+                               kfree_skb(segs);
+                       }
+                       return err;
+               }
+
+               segs = nskb;
+       } while (segs);
+
+       return 0;
 }
 EXPORT_SYMBOL_GPL(xfrm_output);