ChangeSet 1.1982.148.14, 2005/03/03 14:38:31+09:00, [EMAIL PROTECTED]

        [IPV6] Always add a fragment header after receiving TOO BIG w/ pmtu < 
1280.
        
        According to RFC2460, PMTU is set to the IPv6 Minimum Link
        MTU (1280) and a fragment header should always be included
        after a node receiving Too Big message reporting PMTU is
        less than the IPv6 Minimum Link MTU (1280).
        
        Signed-off-by: Hideaki YOSHIFUJI <[EMAIL PROTECTED]>



 include/linux/ip.h        |    1 +
 include/linux/rtnetlink.h |    1 +
 include/net/dst.h         |    9 +++++++++
 net/ipv6/ip6_output.c     |   10 +++++++---
 net/ipv6/route.c          |   34 +++++++++++++++++++++-------------
 5 files changed, 39 insertions(+), 16 deletions(-)


diff -Nru a/include/linux/ip.h b/include/linux/ip.h
--- a/include/linux/ip.h        2005-03-12 20:46:11 -08:00
+++ b/include/linux/ip.h        2005-03-12 20:46:11 -08:00
@@ -152,6 +152,7 @@
 };
 
 #define IPCORK_OPT     1       /* ip-options has been held in ipcork.opt */
+#define IPCORK_ALLFRAG 2       /* always fragment (for ipv6 for now) */
 
 static inline struct inet_sock *inet_sk(const struct sock *sk)
 {
diff -Nru a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h
--- a/include/linux/rtnetlink.h 2005-03-12 20:46:11 -08:00
+++ b/include/linux/rtnetlink.h 2005-03-12 20:46:11 -08:00
@@ -346,6 +346,7 @@
 #define RTAX_FEATURE_ECN       0x00000001
 #define RTAX_FEATURE_SACK      0x00000002
 #define RTAX_FEATURE_TIMESTAMP 0x00000004
+#define RTAX_FEATURE_ALLFRAG   0x00000008
 
 struct rta_session
 {
diff -Nru a/include/net/dst.h b/include/net/dst.h
--- a/include/net/dst.h 2005-03-12 20:46:11 -08:00
+++ b/include/net/dst.h 2005-03-12 20:46:11 -08:00
@@ -124,6 +124,15 @@
        return mtu;
 }
 
+static inline u32
+dst_allfrag(const struct dst_entry *dst)
+{
+       int ret = dst_path_metric(dst, RTAX_FEATURES) & RTAX_FEATURE_ALLFRAG;
+       /* Yes, _exactly_. This is paranoia. */
+       barrier();
+       return ret;
+}
+
 static inline int
 dst_metric_locked(struct dst_entry *dst, int metric)
 {
diff -Nru a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
--- a/net/ipv6/ip6_output.c     2005-03-12 20:46:11 -08:00
+++ b/net/ipv6/ip6_output.c     2005-03-12 20:46:11 -08:00
@@ -147,7 +147,7 @@
 
 int ip6_output(struct sk_buff *skb)
 {
-       if (skb->len > dst_pmtu(skb->dst))
+       if (skb->len > dst_pmtu(skb->dst) || dst_allfrag(skb->dst))
                return ip6_fragment(skb, ip6_output2);
        else
                return ip6_output2(skb);
@@ -848,6 +848,8 @@
                inet->cork.fl = *fl;
                np->cork.hop_limit = hlimit;
                inet->cork.fragsize = mtu = dst_pmtu(&rt->u.dst);
+               if (dst_allfrag(&rt->u.dst))
+                       inet->cork.flags |= IPCORK_ALLFRAG;
                inet->cork.length = 0;
                sk->sk_sndmsg_page = NULL;
                sk->sk_sndmsg_off = 0;
@@ -899,7 +901,7 @@
 
        while (length > 0) {
                /* Check if the remaining data fits into current packet. */
-               copy = mtu - skb->len;
+               copy = (inet->cork.length <= mtu && !(inet->cork.flags & 
IPCORK_ALLFRAG) ? mtu : maxfraglen) - skb->len;
                if (copy < length)
                        copy = maxfraglen - skb->len;
 
@@ -924,7 +926,7 @@
                         * we know we need more fragment(s).
                         */
                        datalen = length + fraggap;
-                       if (datalen > mtu - fragheaderlen)
+                       if (datalen > (inet->cork.length <= mtu && 
!(inet->cork.flags & IPCORK_ALLFRAG) ? mtu : maxfraglen) - fragheaderlen)
                                datalen = maxfraglen - fragheaderlen;
 
                        fraglen = datalen + fragheaderlen;
@@ -1158,6 +1160,7 @@
        if (np->cork.rt) {
                dst_release(&np->cork.rt->u.dst);
                np->cork.rt = NULL;
+               inet->cork.flags &= ~IPCORK_ALLFRAG;
        }
        memset(&inet->cork.fl, 0, sizeof(inet->cork.fl));
        return err;
@@ -1185,6 +1188,7 @@
        if (np->cork.rt) {
                dst_release(&np->cork.rt->u.dst);
                np->cork.rt = NULL;
+               inet->cork.flags &= ~IPCORK_ALLFRAG;
        }
        memset(&inet->cork.fl, 0, sizeof(inet->cork.fl));
 }
diff -Nru a/net/ipv6/route.c b/net/ipv6/route.c
--- a/net/ipv6/route.c  2005-03-12 20:46:11 -08:00
+++ b/net/ipv6/route.c  2005-03-12 20:46:11 -08:00
@@ -628,8 +628,10 @@
 
        if (mtu < dst_pmtu(dst) && rt6->rt6i_dst.plen == 128) {
                rt6->rt6i_flags |= RTF_MODIFIED;
-               if (mtu < IPV6_MIN_MTU)
+               if (mtu < IPV6_MIN_MTU) {
                        mtu = IPV6_MIN_MTU;
+                       dst->metrics[RTAX_FEATURES-1] |= RTAX_FEATURE_ALLFRAG;
+               }
                dst->metrics[RTAX_MTU-1] = mtu;
        }
 }
@@ -1164,26 +1166,26 @@
                        struct net_device *dev, u32 pmtu)
 {
        struct rt6_info *rt, *nrt;
-
-       if (pmtu < IPV6_MIN_MTU) {
-               if (net_ratelimit())
-                       printk(KERN_DEBUG "rt6_pmtu_discovery: invalid MTU 
value %d\n",
-                              pmtu);
-               /* According to RFC1981, the PMTU is set to the IPv6 minimum
-                  link MTU if the node receives a Packet Too Big message
-                  reporting next-hop MTU that is less than the IPv6 minimum 
MTU.
-                  */
-               pmtu = IPV6_MIN_MTU;
-       }
+       int allfrag = 0;
 
        rt = rt6_lookup(daddr, saddr, dev->ifindex, 0);
-
        if (rt == NULL)
                return;
 
        if (pmtu >= dst_pmtu(&rt->u.dst))
                goto out;
 
+       if (pmtu < IPV6_MIN_MTU) {
+               /*
+                * According to RFC2460, PMTU is set to the IPv6 Minimum Link 
+                * MTU (1280) and a fragment header should always be included
+                * after a node receiving Too Big message reporting PMTU is
+                * less than the IPv6 Minimum Link MTU.
+                */
+               pmtu = IPV6_MIN_MTU;
+               allfrag = 1;
+       }
+
        /* New mtu received -> path was valid.
           They are sent only in response to data packets,
           so that this nexthop apparently is reachable. --ANK
@@ -1197,6 +1199,8 @@
         */
        if (rt->rt6i_flags & RTF_CACHE) {
                rt->u.dst.metrics[RTAX_MTU-1] = pmtu;
+               if (allfrag)
+                       rt->u.dst.metrics[RTAX_FEATURES-1] |= 
RTAX_FEATURE_ALLFRAG;
                dst_set_expires(&rt->u.dst, ip6_rt_mtu_expires);
                rt->rt6i_flags |= RTF_MODIFIED|RTF_EXPIRES;
                goto out;
@@ -1211,6 +1215,8 @@
                nrt = rt6_cow(rt, daddr, saddr);
                if (!nrt->u.dst.error) {
                        nrt->u.dst.metrics[RTAX_MTU-1] = pmtu;
+                       if (allfrag)
+                               nrt->u.dst.metrics[RTAX_FEATURES-1] |= 
RTAX_FEATURE_ALLFRAG;
                        /* According to RFC 1981, detecting PMTU increase 
shouldn't be
                           happened within 5 mins, the recommended timer is 10 
mins.
                           Here this route expiration time is set to 
ip6_rt_mtu_expires
@@ -1232,6 +1238,8 @@
                dst_set_expires(&nrt->u.dst, ip6_rt_mtu_expires);
                nrt->rt6i_flags |= RTF_DYNAMIC|RTF_CACHE|RTF_EXPIRES;
                nrt->u.dst.metrics[RTAX_MTU-1] = pmtu;
+               if (allfrag)
+                       nrt->u.dst.metrics[RTAX_FEATURES-1] |= 
RTAX_FEATURE_ALLFRAG;
                ip6_ins_rt(nrt, NULL, NULL);
        }
 
-
To unsubscribe from this list: send the line "unsubscribe bk-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to