ipv6: Fragment locally generated tunnel-mode IPSec6 packets as needed.
authorDavid Stevens <dlstevens@us.ibm.com>
Fri, 17 Dec 2010 11:42:42 +0000 (11:42 +0000)
committerDavid S. Miller <davem@davemloft.net>
Mon, 20 Dec 2010 04:22:23 +0000 (20:22 -0800)
This patch modifies IPsec6 to fragment IPv6 packets that are
locally generated as needed.

This version of the patch only fragments in tunnel mode, so that fragment
headers will not be obscured by ESP in transport mode.

Signed-off-by: David L Stevens <dlstevens@us.ibm.com>
Acked-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/ip6_route.h
net/ipv6/ip6_output.c
net/ipv6/xfrm6_output.c

index 278312c95f9600bd863fa0dc76c52a7c048a9d19..2ab926860cd855b6ec7861a998d19612624980e6 100644 (file)
@@ -164,5 +164,15 @@ static inline int ipv6_unicast_destination(struct sk_buff *skb)
        return rt->rt6i_flags & RTF_LOCAL;
 }
 
+int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *));
+
+static inline int ip6_skb_dst_mtu(struct sk_buff *skb)
+{
+       struct ipv6_pinfo *np = skb->sk ? inet6_sk(skb->sk) : NULL;
+
+       return (np && np->pmtudisc == IPV6_PMTUDISC_PROBE) ?
+              skb_dst(skb)->dev->mtu : dst_mtu(skb_dst(skb));
+}
+
 #endif
 #endif
index 99157b4cd56e2fa619939a17aa5b716680fc8799..94b5bf132b2e33a467f662b8c0e402a459f00a3d 100644 (file)
@@ -56,7 +56,7 @@
 #include <net/checksum.h>
 #include <linux/mroute6.h>
 
-static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *));
+int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *));
 
 int __ip6_local_out(struct sk_buff *skb)
 {
@@ -145,14 +145,6 @@ static int ip6_finish_output2(struct sk_buff *skb)
        return -EINVAL;
 }
 
-static inline int ip6_skb_dst_mtu(struct sk_buff *skb)
-{
-       struct ipv6_pinfo *np = skb->sk ? inet6_sk(skb->sk) : NULL;
-
-       return (np && np->pmtudisc == IPV6_PMTUDISC_PROBE) ?
-              skb_dst(skb)->dev->mtu : dst_mtu(skb_dst(skb));
-}
-
 static int ip6_finish_output(struct sk_buff *skb)
 {
        if ((skb->len > ip6_skb_dst_mtu(skb) && !skb_is_gso(skb)) ||
@@ -601,7 +593,7 @@ int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr)
        return offset;
 }
 
-static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
+int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
 {
        struct sk_buff *frag;
        struct rt6_info *rt = (struct rt6_info*)skb_dst(skb);
index 6434bd5ce0885ad20408a2f79eb198b8f30c269a..8e688b3de9abc62ec03c7dd90b33c951791c5587 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/netfilter_ipv6.h>
 #include <net/dst.h>
 #include <net/ipv6.h>
+#include <net/ip6_route.h>
 #include <net/xfrm.h>
 
 int xfrm6_find_1stfragopt(struct xfrm_state *x, struct sk_buff *skb,
@@ -88,8 +89,21 @@ static int xfrm6_output_finish(struct sk_buff *skb)
        return xfrm_output(skb);
 }
 
+static int __xfrm6_output(struct sk_buff *skb)
+{
+       struct dst_entry *dst = skb_dst(skb);
+       struct xfrm_state *x = dst->xfrm;
+
+       if ((x && x->props.mode == XFRM_MODE_TUNNEL) &&
+           ((skb->len > ip6_skb_dst_mtu(skb) && !skb_is_gso(skb)) ||
+               dst_allfrag(skb_dst(skb)))) {
+                       return ip6_fragment(skb, xfrm6_output_finish);
+       }
+       return xfrm6_output_finish(skb);
+}
+
 int xfrm6_output(struct sk_buff *skb)
 {
        return NF_HOOK(NFPROTO_IPV6, NF_INET_POST_ROUTING, skb, NULL,
-                      skb_dst(skb)->dev, xfrm6_output_finish);
+                      skb_dst(skb)->dev, __xfrm6_output);
 }