|
|
48f65f6 |
From 0d3f6d297bfb7af24d0508460fdb3d1ec4903fa3 Mon Sep 17 00:00:00 2001
|
|
|
48f65f6 |
From: Martin KaFai Lau <kafai@fb.com>
|
|
|
48f65f6 |
Date: Wed, 11 Nov 2015 11:51:06 -0800
|
|
|
48f65f6 |
Subject: [PATCH] ipv6: Avoid creating RTF_CACHE from a rt that is not managed
|
|
|
48f65f6 |
by fib6 tree
|
|
|
48f65f6 |
|
|
|
48f65f6 |
The original bug report:
|
|
|
48f65f6 |
https://bugzilla.redhat.com/show_bug.cgi?id=1272571
|
|
|
48f65f6 |
|
|
|
48f65f6 |
The setup has a IPv4 GRE tunnel running in a IPSec. The bug
|
|
|
48f65f6 |
happens when ndisc starts sending router solicitation at the gre
|
|
|
48f65f6 |
interface. The simplified oops stack is like:
|
|
|
48f65f6 |
|
|
|
48f65f6 |
__lock_acquire+0x1b2/0x1c30
|
|
|
48f65f6 |
lock_acquire+0xb9/0x140
|
|
|
48f65f6 |
_raw_write_lock_bh+0x3f/0x50
|
|
|
48f65f6 |
__ip6_ins_rt+0x2e/0x60
|
|
|
48f65f6 |
ip6_ins_rt+0x49/0x50
|
|
|
48f65f6 |
~~~~~~~~
|
|
|
48f65f6 |
__ip6_rt_update_pmtu.part.54+0x145/0x250
|
|
|
48f65f6 |
ip6_rt_update_pmtu+0x2e/0x40
|
|
|
48f65f6 |
~~~~~~~~
|
|
|
48f65f6 |
ip_tunnel_xmit+0x1f1/0xf40
|
|
|
48f65f6 |
__gre_xmit+0x7a/0x90
|
|
|
48f65f6 |
ipgre_xmit+0x15a/0x220
|
|
|
48f65f6 |
dev_hard_start_xmit+0x2bd/0x480
|
|
|
48f65f6 |
__dev_queue_xmit+0x696/0x730
|
|
|
48f65f6 |
dev_queue_xmit+0x10/0x20
|
|
|
48f65f6 |
neigh_direct_output+0x11/0x20
|
|
|
48f65f6 |
ip6_finish_output2+0x21f/0x770
|
|
|
48f65f6 |
ip6_finish_output+0xa7/0x1d0
|
|
|
48f65f6 |
ip6_output+0x56/0x190
|
|
|
48f65f6 |
~~~~~~~~
|
|
|
48f65f6 |
ndisc_send_skb+0x1d9/0x400
|
|
|
48f65f6 |
ndisc_send_rs+0x88/0xc0
|
|
|
48f65f6 |
~~~~~~~~
|
|
|
48f65f6 |
|
|
|
48f65f6 |
The rt passed to ip6_rt_update_pmtu() is created by
|
|
|
48f65f6 |
icmp6_dst_alloc() and it is not managed by the fib6 tree,
|
|
|
48f65f6 |
so its rt6i_table == NULL. When __ip6_rt_update_pmtu() creates
|
|
|
48f65f6 |
a RTF_CACHE clone, the newly created clone also has rt6i_table == NULL
|
|
|
48f65f6 |
and it causes the ip6_ins_rt() oops.
|
|
|
48f65f6 |
|
|
|
48f65f6 |
During pmtu update, we only want to create a RTF_CACHE clone
|
|
|
48f65f6 |
from a rt which is currently managed (or owned) by the
|
|
|
48f65f6 |
fib6 tree. It means either rt->rt6i_node != NULL or
|
|
|
48f65f6 |
rt is a RTF_PCPU clone.
|
|
|
48f65f6 |
|
|
|
48f65f6 |
It is worth to note that rt6i_table may not be NULL even it is
|
|
|
48f65f6 |
not (yet) managed by the fib6 tree (e.g. addrconf_dst_alloc()).
|
|
|
48f65f6 |
Hence, rt6i_node is a better check instead of rt6i_table.
|
|
|
48f65f6 |
|
|
|
48f65f6 |
Fixes: 45e4fd26683c ("ipv6: Only create RTF_CACHE routes after encountering pmtu")
|
|
|
48f65f6 |
Signed-off-by: Martin KaFai Lau <kafai@fb.com>
|
|
|
48f65f6 |
Reported-by: Chris Siebenmann <cks-rhbugzilla@cs.toronto.edu>
|
|
|
48f65f6 |
Cc: Chris Siebenmann <cks-rhbugzilla@cs.toronto.edu>
|
|
|
48f65f6 |
Cc: Hannes Frederic Sowa <hannes@stressinduktion.org>
|
|
|
48f65f6 |
Signed-off-by: David S. Miller <davem@davemloft.net>
|
|
|
48f65f6 |
---
|
|
|
48f65f6 |
net/ipv6/route.c | 8 +++++++-
|
|
|
48f65f6 |
1 file changed, 7 insertions(+), 1 deletion(-)
|
|
|
48f65f6 |
|
|
|
48f65f6 |
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
|
|
|
48f65f6 |
index c8bc9b4..74907c5 100644
|
|
|
48f65f6 |
--- a/net/ipv6/route.c
|
|
|
48f65f6 |
+++ b/net/ipv6/route.c
|
|
|
48f65f6 |
@@ -1322,6 +1322,12 @@ static void rt6_do_update_pmtu(struct rt6_info *rt, u32 mtu)
|
|
|
48f65f6 |
rt6_update_expires(rt, net->ipv6.sysctl.ip6_rt_mtu_expires);
|
|
|
48f65f6 |
}
|
|
|
48f65f6 |
|
|
|
48f65f6 |
+static bool rt6_cache_allowed_for_pmtu(const struct rt6_info *rt)
|
|
|
48f65f6 |
+{
|
|
|
48f65f6 |
+ return !(rt->rt6i_flags & RTF_CACHE) &&
|
|
|
48f65f6 |
+ (rt->rt6i_flags & RTF_PCPU || rt->rt6i_node);
|
|
|
48f65f6 |
+}
|
|
|
48f65f6 |
+
|
|
|
48f65f6 |
static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk,
|
|
|
48f65f6 |
const struct ipv6hdr *iph, u32 mtu)
|
|
|
48f65f6 |
{
|
|
|
48f65f6 |
@@ -1335,7 +1341,7 @@ static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk,
|
|
|
48f65f6 |
if (mtu >= dst_mtu(dst))
|
|
|
48f65f6 |
return;
|
|
|
48f65f6 |
|
|
|
48f65f6 |
- if (rt6->rt6i_flags & RTF_CACHE) {
|
|
|
48f65f6 |
+ if (!rt6_cache_allowed_for_pmtu(rt6)) {
|
|
|
48f65f6 |
rt6_do_update_pmtu(rt6, mtu);
|
|
|
48f65f6 |
} else {
|
|
|
48f65f6 |
const struct in6_addr *daddr, *saddr;
|
|
|
48f65f6 |
--
|
|
|
48f65f6 |
2.5.0
|
|
|
48f65f6 |
|