diff options
author | Eric Dumazet <dada1@cosmosbay.com> | 2008-01-18 04:30:21 -0800 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-01-20 20:31:39 -0800 |
commit | 8d3f099abe25c21670cb5728178a1f286952782d (patch) | |
tree | 074339fd500a3af4f89cab67c0a90bae81bc93a7 /net | |
parent | 49d85c502ec5e6d5998c1a04394c5b24e8f7d32d (diff) | |
download | linux-8d3f099abe25c21670cb5728178a1f286952782d.tar.gz linux-8d3f099abe25c21670cb5728178a1f286952782d.tar.bz2 linux-8d3f099abe25c21670cb5728178a1f286952782d.zip |
[IPV4] FIB_HASH : Avoid unecessary loop in fn_hash_dump_zone()
I noticed "ip route list" was slower than "cat /proc/net/route" on a
machine with a full Internet routing table (214392 entries : Special
thanks to Robert ;) )
This is similar to problem reported in commit
d8c9283089287341c85a0a69de32c2287a990e71 ("[IPV4] ROUTE: ip_rt_dump()
is unecessary slow")
Fix is to avoid scanning the begining of fz_hash table, but directly
seek to the right offset.
Before patch :
time ip route >/tmp/ROUTE
real 0m1.285s
user 0m0.712s
sys 0m0.436s
After patch
# time ip route >/tmp/ROUTE
real 0m0.835s
user 0m0.692s
sys 0m0.124s
Signed-off-by: Eric Dumazet <dada1@cosmosbay.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv4/fib_hash.c | 20 |
1 files changed, 9 insertions, 11 deletions
diff --git a/net/ipv4/fib_hash.c b/net/ipv4/fib_hash.c index 99071d79c5e7..0dfee27cfbcd 100644 --- a/net/ipv4/fib_hash.c +++ b/net/ipv4/fib_hash.c @@ -721,19 +721,18 @@ fn_hash_dump_zone(struct sk_buff *skb, struct netlink_callback *cb, { int h, s_h; + if (fz->fz_hash == NULL) + return skb->len; s_h = cb->args[3]; - for (h=0; h < fz->fz_divisor; h++) { - if (h < s_h) continue; - if (h > s_h) - memset(&cb->args[4], 0, - sizeof(cb->args) - 4*sizeof(cb->args[0])); - if (fz->fz_hash == NULL || - hlist_empty(&fz->fz_hash[h])) + for (h = s_h; h < fz->fz_divisor; h++) { + if (hlist_empty(&fz->fz_hash[h])) continue; - if (fn_hash_dump_bucket(skb, cb, tb, fz, &fz->fz_hash[h])<0) { + if (fn_hash_dump_bucket(skb, cb, tb, fz, &fz->fz_hash[h]) < 0) { cb->args[3] = h; return -1; } + memset(&cb->args[4], 0, + sizeof(cb->args) - 4*sizeof(cb->args[0])); } cb->args[3] = h; return skb->len; @@ -749,14 +748,13 @@ static int fn_hash_dump(struct fib_table *tb, struct sk_buff *skb, struct netlin read_lock(&fib_hash_lock); for (fz = table->fn_zone_list, m=0; fz; fz = fz->fz_next, m++) { if (m < s_m) continue; - if (m > s_m) - memset(&cb->args[3], 0, - sizeof(cb->args) - 3*sizeof(cb->args[0])); if (fn_hash_dump_zone(skb, cb, tb, fz) < 0) { cb->args[2] = m; read_unlock(&fib_hash_lock); return -1; } + memset(&cb->args[3], 0, + sizeof(cb->args) - 3*sizeof(cb->args[0])); } read_unlock(&fib_hash_lock); cb->args[2] = m; |