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