diff options
author | Sabrina Dubroca <sd@queasysnail.net> | 2018-03-14 10:21:14 +0100 |
---|---|---|
committer | Ben Hutchings <ben@decadent.org.uk> | 2018-06-16 22:22:39 +0100 |
commit | df9ece1148e2ec242871623dedb004f7a1387125 (patch) | |
tree | 5dc37ff111d04b51c9ad3b5142b70b028ddafe0d /include | |
parent | bc7d5ec532ca5c3ea44b2b488f3342fef3d7a90f (diff) |
ipv4: lock mtu in fnhe when received PMTU < net.ipv4.route.min_pmtu
commit d52e5a7e7ca49457dd31fc8b42fb7c0d58a31221 upstream.
Prior to the rework of PMTU information storage in commit
2c8cec5c10bc ("ipv4: Cache learned PMTU information in inetpeer."),
when a PMTU event advertising a PMTU smaller than
net.ipv4.route.min_pmtu was received, we would disable setting the DF
flag on packets by locking the MTU metric, and set the PMTU to
net.ipv4.route.min_pmtu.
Since then, we don't disable DF, and set PMTU to
net.ipv4.route.min_pmtu, so the intermediate router that has this link
with a small MTU will have to drop the packets.
This patch reestablishes pre-2.6.39 behavior by splitting
rtable->rt_pmtu into a bitfield with rt_mtu_locked and rt_pmtu.
rt_mtu_locked indicates that we shouldn't set the DF bit on that path,
and is checked in ip_dont_fragment().
One possible workaround is to set net.ipv4.route.min_pmtu to a value low
enough to accommodate the lowest MTU encountered.
Fixes: 2c8cec5c10bc ("ipv4: Cache learned PMTU information in inetpeer.")
Signed-off-by: Sabrina Dubroca <sd@queasysnail.net>
Reviewed-by: Stefano Brivio <sbrivio@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
[bwh: Backported to 3.16: adjust context]
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
Diffstat (limited to 'include')
-rw-r--r-- | include/net/ip.h | 11 | ||||
-rw-r--r-- | include/net/ip_fib.h | 1 | ||||
-rw-r--r-- | include/net/route.h | 3 |
3 files changed, 12 insertions, 3 deletions
diff --git a/include/net/ip.h b/include/net/ip.h index 3d389a86a7e2..27dd9826e05d 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -263,12 +263,19 @@ int ip_decrease_ttl(struct iphdr *iph) return --iph->ttl; } +static inline int ip_mtu_locked(const struct dst_entry *dst) +{ + const struct rtable *rt = (const struct rtable *)dst; + + return rt->rt_mtu_locked || dst_metric_locked(dst, RTAX_MTU); +} + static inline int ip_dont_fragment(struct sock *sk, struct dst_entry *dst) { return inet_sk(sk)->pmtudisc == IP_PMTUDISC_DO || (inet_sk(sk)->pmtudisc == IP_PMTUDISC_WANT && - !(dst_metric_locked(dst, RTAX_MTU))); + !ip_mtu_locked(dst)); } static inline bool ip_sk_accept_pmtu(const struct sock *sk) @@ -294,7 +301,7 @@ static inline unsigned int ip_dst_mtu_maybe_forward(const struct dst_entry *dst, struct net *net = dev_net(dst->dev); if (net->ipv4.sysctl_ip_fwd_use_pmtu || - dst_metric_locked(dst, RTAX_MTU) || + ip_mtu_locked(dst) || !forwarding) return dst_mtu(dst); diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h index fc7014fe8ee3..905cd10a9478 100644 --- a/include/net/ip_fib.h +++ b/include/net/ip_fib.h @@ -54,6 +54,7 @@ struct fib_nh_exception { int fnhe_genid; __be32 fnhe_daddr; u32 fnhe_pmtu; + bool fnhe_mtu_locked; __be32 fnhe_gw; unsigned long fnhe_expires; struct rtable __rcu *fnhe_rth_input; diff --git a/include/net/route.h b/include/net/route.h index 671d5b1c813b..6de6c4977d07 100644 --- a/include/net/route.h +++ b/include/net/route.h @@ -61,7 +61,8 @@ struct rtable { __be32 rt_gateway; /* Miscellaneous cached information */ - u32 rt_pmtu; + u32 rt_mtu_locked:1, + rt_pmtu:31; struct list_head rt_uncached; }; |