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