Commit 7197ce26 authored by Alexey Kuznetsov's avatar Alexey Kuznetsov Committed by David S. Miller

[IPV4]: More sane rtcache behavior.

1) More reasonable ip_rt_gc_min_interval default
2) Trim less valuable entries in hash chain during
   rt_intern_hash when such chains grow too long.
parent 3eef54d7
...@@ -111,7 +111,7 @@ int ip_rt_max_delay = 10 * HZ; ...@@ -111,7 +111,7 @@ int ip_rt_max_delay = 10 * HZ;
int ip_rt_max_size; int ip_rt_max_size;
int ip_rt_gc_timeout = RT_GC_TIMEOUT; int ip_rt_gc_timeout = RT_GC_TIMEOUT;
int ip_rt_gc_interval = 60 * HZ; int ip_rt_gc_interval = 60 * HZ;
int ip_rt_gc_min_interval = 5 * HZ; int ip_rt_gc_min_interval = HZ / 2;
int ip_rt_redirect_number = 9; int ip_rt_redirect_number = 9;
int ip_rt_redirect_load = HZ / 50; int ip_rt_redirect_load = HZ / 50;
int ip_rt_redirect_silence = ((HZ / 50) << (9 + 1)); int ip_rt_redirect_silence = ((HZ / 50) << (9 + 1));
...@@ -456,6 +456,25 @@ static int rt_may_expire(struct rtable *rth, unsigned long tmo1, unsigned long t ...@@ -456,6 +456,25 @@ static int rt_may_expire(struct rtable *rth, unsigned long tmo1, unsigned long t
out: return ret; out: return ret;
} }
/* Bits of score are:
* 31: very valuable
* 30: not quite useless
* 29..0: usage counter
*/
static inline u32 rt_score(struct rtable *rt)
{
u32 score = rt->u.dst.__use;
if (rt_valuable(rt))
score |= (1<<31);
if (!rt->fl.iif ||
!(rt->rt_flags & (RTCF_BROADCAST|RTCF_MULTICAST|RTCF_LOCAL)))
score |= (1<<30);
return score;
}
/* This runs via a timer and thus is always in BH context. */ /* This runs via a timer and thus is always in BH context. */
static void rt_check_expire(unsigned long dummy) static void rt_check_expire(unsigned long dummy)
{ {
...@@ -721,6 +740,9 @@ static int rt_intern_hash(unsigned hash, struct rtable *rt, struct rtable **rp) ...@@ -721,6 +740,9 @@ static int rt_intern_hash(unsigned hash, struct rtable *rt, struct rtable **rp)
{ {
struct rtable *rth, **rthp; struct rtable *rth, **rthp;
unsigned long now = jiffies; unsigned long now = jiffies;
struct rtable *cand = NULL, **candp = NULL;
u32 min_score = ~(u32)0;
int chain_length = 0;
int attempts = !in_softirq(); int attempts = !in_softirq();
restart: restart:
...@@ -755,9 +777,35 @@ static int rt_intern_hash(unsigned hash, struct rtable *rt, struct rtable **rp) ...@@ -755,9 +777,35 @@ static int rt_intern_hash(unsigned hash, struct rtable *rt, struct rtable **rp)
return 0; return 0;
} }
if (!atomic_read(&rth->u.dst.__refcnt)) {
u32 score = rt_score(rth);
if (score <= min_score) {
cand = rth;
candp = rthp;
min_score = score;
}
}
chain_length++;
rthp = &rth->u.rt_next; rthp = &rth->u.rt_next;
} }
if (cand) {
/* ip_rt_gc_elasticity used to be average length of chain
* length, when exceeded gc becomes really aggressive.
*
* The second limit is less certain. At the moment it allows
* only 2 entries per bucket. We will see.
*/
if (chain_length > ip_rt_gc_elasticity ||
(chain_length > 1 && !(min_score & (1<<31)))) {
*candp = cand->u.rt_next;
rt_free(cand);
}
}
/* Try to bind route to arp only if it is output /* Try to bind route to arp only if it is output
route or unicast forwarding path. route or unicast forwarding path.
*/ */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment