Commit 8d3f099a authored by Eric Dumazet's avatar Eric Dumazet Committed by David S. Miller

[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
d8c92830 ("[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: default avatarEric Dumazet <dada1@cosmosbay.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 49d85c50
...@@ -721,19 +721,18 @@ fn_hash_dump_zone(struct sk_buff *skb, struct netlink_callback *cb, ...@@ -721,19 +721,18 @@ fn_hash_dump_zone(struct sk_buff *skb, struct netlink_callback *cb,
{ {
int h, s_h; int h, s_h;
if (fz->fz_hash == NULL)
return skb->len;
s_h = cb->args[3]; s_h = cb->args[3];
for (h=0; h < fz->fz_divisor; h++) { for (h = s_h; h < fz->fz_divisor; h++) {
if (h < s_h) continue; if (hlist_empty(&fz->fz_hash[h]))
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]))
continue; 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; cb->args[3] = h;
return -1; return -1;
} }
memset(&cb->args[4], 0,
sizeof(cb->args) - 4*sizeof(cb->args[0]));
} }
cb->args[3] = h; cb->args[3] = h;
return skb->len; return skb->len;
...@@ -749,14 +748,13 @@ static int fn_hash_dump(struct fib_table *tb, struct sk_buff *skb, struct netlin ...@@ -749,14 +748,13 @@ static int fn_hash_dump(struct fib_table *tb, struct sk_buff *skb, struct netlin
read_lock(&fib_hash_lock); read_lock(&fib_hash_lock);
for (fz = table->fn_zone_list, m=0; fz; fz = fz->fz_next, m++) { for (fz = table->fn_zone_list, m=0; fz; fz = fz->fz_next, m++) {
if (m < s_m) continue; 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) { if (fn_hash_dump_zone(skb, cb, tb, fz) < 0) {
cb->args[2] = m; cb->args[2] = m;
read_unlock(&fib_hash_lock); read_unlock(&fib_hash_lock);
return -1; return -1;
} }
memset(&cb->args[3], 0,
sizeof(cb->args) - 3*sizeof(cb->args[0]));
} }
read_unlock(&fib_hash_lock); read_unlock(&fib_hash_lock);
cb->args[2] = m; cb->args[2] = m;
......
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