1 From 83c97c9fbcefcc759abf935de7d4b9ce99675b68 Mon Sep 17 00:00:00 2001
2 From: Neil Horman <nhorman@tuxdriver.com>
3 Date: Fri, 26 Jun 2009 11:41:16 -0700
4 Subject: ipv4 routing: Ensure that route cache entries are usable and reclaimable with caching is off
6 From: Neil Horman <nhorman@tuxdriver.com>
8 [ Upstream commit b6280b47a7a42970d098a3059f4ebe7e55e90d8d ]
10 When route caching is disabled (rt_caching returns false), We still use route
11 cache entries that are created and passed into rt_intern_hash once. These
12 routes need to be made usable for the one call path that holds a reference to
13 them, and they need to be reclaimed when they're finished with their use. To be
14 made usable, they need to be associated with a neighbor table entry (which they
15 currently are not), otherwise iproute_finish2 just discards the packet, since we
16 don't know which L2 peer to send the packet to. To do this binding, we need to
17 follow the path a bit higher up in rt_intern_hash, which calls
18 arp_bind_neighbour, but not assign the route entry to the hash table.
19 Currently, if caching is off, we simply assign the route to the rp pointer and
20 are reutrn success. This patch associates us with a neighbor entry first.
22 Secondly, we need to make sure that any single use routes like this are known to
23 the garbage collector when caching is off. If caching is off, and we try to
24 hash in a route, it will leak when its refcount reaches zero. To avoid this,
25 this patch calls rt_free on the route cache entry passed into rt_intern_hash.
26 This places us on the gc list for the route cache garbage collector, so that
27 when its refcount reaches zero, it will be reclaimed (Thanks to Alexey for this
30 I've tested this on a local system here, and with these patches in place, I'm
31 able to maintain routed connectivity to remote systems, even if I set
32 /proc/sys/net/ipv4/rt_cache_rebuild_count to -1, which forces rt_caching to
35 Signed-off-by: Neil Horman <nhorman@redhat.com>
36 Reported-by: Jarek Poplawski <jarkao2@gmail.com>
37 Reported-by: Maxime Bizon <mbizon@freebox.fr>
38 Signed-off-by: David S. Miller <davem@davemloft.net>
39 Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
42 net/ipv4/route.c | 26 +++++++++++++++++++++++---
43 1 file changed, 23 insertions(+), 3 deletions(-)
45 --- a/net/ipv4/route.c
46 +++ b/net/ipv4/route.c
47 @@ -1089,8 +1089,27 @@ restart:
48 * If we drop it here, the callers have no way to resolve routes
49 * when we're not caching. Instead, just point *rp at rt, so
50 * the caller gets a single use out of the route
51 + * Note that we do rt_free on this new route entry, so that
52 + * once its refcount hits zero, we are still able to reap it
54 + * Note also the rt_free uses call_rcu. We don't actually
55 + * need rcu protection here, this is just our path to get
56 + * on the route gc list.
58 - goto report_and_exit;
60 + if (rt->rt_type == RTN_UNICAST || rt->fl.iif == 0) {
61 + int err = arp_bind_neighbour(&rt->u.dst);
63 + if (net_ratelimit())
65 + "Neighbour table failure & not caching routes.\n");
75 rthp = &rt_hash_table[hash].chain;
76 @@ -1204,7 +1223,8 @@ restart:
77 #if RT_CACHE_DEBUG >= 2
78 if (rt->u.dst.rt_next) {
80 - printk(KERN_DEBUG "rt_cache @%02x: %pI4", hash, &rt->rt_dst);
81 + printk(KERN_DEBUG "rt_cache @%02x: %pI4",
83 for (trt = rt->u.dst.rt_next; trt; trt = trt->u.dst.rt_next)
84 printk(" . %pI4", &trt->rt_dst);
86 @@ -1219,7 +1239,7 @@ restart:
88 spin_unlock_bh(rt_hash_lock_addr(hash));