aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--net/ipv4/route.c26
1 files changed, 23 insertions, 3 deletions
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 4dae83fdb27..d777f845ed1 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -1089,8 +1089,27 @@ restart:
* If we drop it here, the callers have no way to resolve routes
* when we're not caching. Instead, just point *rp at rt, so
* the caller gets a single use out of the route
+ * Note that we do rt_free on this new route entry, so that
+ * once its refcount hits zero, we are still able to reap it
+ * (Thanks Alexey)
+ * Note also the rt_free uses call_rcu. We don't actually
+ * need rcu protection here, this is just our path to get
+ * on the route gc list.
*/
- goto report_and_exit;
+
+ if (rt->rt_type == RTN_UNICAST || rt->fl.iif == 0) {
+ int err = arp_bind_neighbour(&rt->u.dst);
+ if (err) {
+ if (net_ratelimit())
+ printk(KERN_WARNING
+ "Neighbour table failure & not caching routes.\n");
+ rt_drop(rt);
+ return err;
+ }
+ }
+
+ rt_free(rt);
+ goto skip_hashing;
}
rthp = &rt_hash_table[hash].chain;
@@ -1204,7 +1223,8 @@ restart:
#if RT_CACHE_DEBUG >= 2
if (rt->u.dst.rt_next) {
struct rtable *trt;
- printk(KERN_DEBUG "rt_cache @%02x: %pI4", hash, &rt->rt_dst);
+ printk(KERN_DEBUG "rt_cache @%02x: %pI4",
+ hash, &rt->rt_dst);
for (trt = rt->u.dst.rt_next; trt; trt = trt->u.dst.rt_next)
printk(" . %pI4", &trt->rt_dst);
printk("\n");
@@ -1219,7 +1239,7 @@ restart:
spin_unlock_bh(rt_hash_lock_addr(hash));
-report_and_exit:
+skip_hashing:
*rp = rt;
return 0;
}