summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorSabrina Dubroca <sd@queasysnail.net>2018-03-14 10:21:14 +0100
committerBen Hutchings <ben@decadent.org.uk>2018-06-16 22:22:39 +0100
commitdf9ece1148e2ec242871623dedb004f7a1387125 (patch)
tree5dc37ff111d04b51c9ad3b5142b70b028ddafe0d /include
parentbc7d5ec532ca5c3ea44b2b488f3342fef3d7a90f (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.h11
-rw-r--r--include/net/ip_fib.h1
-rw-r--r--include/net/route.h3
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;
};