aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Hemminger <shemminger@vyatta.com>2008-02-12 00:14:39 -0500
committerDavid S. Miller <davem@davemloft.net>2008-02-12 20:53:31 -0500
commit8315f5d80a90247bf92232f92ca49933ac49327b (patch)
tree690332d077339b2d0c93280f08f6fbe9f5b371c7
parentec28cf738d899e9d0652108e1986101771aacb2e (diff)
fib_trie: /proc/net/route performance improvement
Use key/offset caching to change /proc/net/route (use by iputils route) from O(n^2) to O(n). This improves performance from 30sec with 160,000 routes to 1sec. Signed-off-by: Stephen Hemminger <shemminger@vyatta.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/ipv4/fib_trie.c93
1 files changed, 82 insertions, 11 deletions
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index 2d895274b7f8..1ff446d0fa8b 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -2459,6 +2459,84 @@ static const struct file_operations fib_trie_fops = {
2459 .release = seq_release_net, 2459 .release = seq_release_net,
2460}; 2460};
2461 2461
2462struct fib_route_iter {
2463 struct seq_net_private p;
2464 struct trie *main_trie;
2465 loff_t pos;
2466 t_key key;
2467};
2468
2469static struct leaf *fib_route_get_idx(struct fib_route_iter *iter, loff_t pos)
2470{
2471 struct leaf *l = NULL;
2472 struct trie *t = iter->main_trie;
2473
2474 /* use cache location of last found key */
2475 if (iter->pos > 0 && pos >= iter->pos && (l = fib_find_node(t, iter->key)))
2476 pos -= iter->pos;
2477 else {
2478 iter->pos = 0;
2479 l = trie_firstleaf(t);
2480 }
2481
2482 while (l && pos-- > 0) {
2483 iter->pos++;
2484 l = trie_nextleaf(l);
2485 }
2486
2487 if (l)
2488 iter->key = pos; /* remember it */
2489 else
2490 iter->pos = 0; /* forget it */
2491
2492 return l;
2493}
2494
2495static void *fib_route_seq_start(struct seq_file *seq, loff_t *pos)
2496 __acquires(RCU)
2497{
2498 struct fib_route_iter *iter = seq->private;
2499 struct fib_table *tb;
2500
2501 rcu_read_lock();
2502 tb = fib_get_table(iter->p.net, RT_TABLE_MAIN);
2503 if (!tb)
2504 return NULL;
2505
2506 iter->main_trie = (struct trie *) tb->tb_data;
2507 if (*pos == 0)
2508 return SEQ_START_TOKEN;
2509 else
2510 return fib_route_get_idx(iter, *pos - 1);
2511}
2512
2513static void *fib_route_seq_next(struct seq_file *seq, void *v, loff_t *pos)
2514{
2515 struct fib_route_iter *iter = seq->private;
2516 struct leaf *l = v;
2517
2518 ++*pos;
2519 if (v == SEQ_START_TOKEN) {
2520 iter->pos = 0;
2521 l = trie_firstleaf(iter->main_trie);
2522 } else {
2523 iter->pos++;
2524 l = trie_nextleaf(l);
2525 }
2526
2527 if (l)
2528 iter->key = l->key;
2529 else
2530 iter->pos = 0;
2531 return l;
2532}
2533
2534static void fib_route_seq_stop(struct seq_file *seq, void *v)
2535 __releases(RCU)
2536{
2537 rcu_read_unlock();
2538}
2539
2462static unsigned fib_flag_trans(int type, __be32 mask, const struct fib_info *fi) 2540static unsigned fib_flag_trans(int type, __be32 mask, const struct fib_info *fi)
2463{ 2541{
2464 static unsigned type2flags[RTN_MAX + 1] = { 2542 static unsigned type2flags[RTN_MAX + 1] = {
@@ -2482,7 +2560,6 @@ static unsigned fib_flag_trans(int type, __be32 mask, const struct fib_info *fi)
2482 */ 2560 */
2483static int fib_route_seq_show(struct seq_file *seq, void *v) 2561static int fib_route_seq_show(struct seq_file *seq, void *v)
2484{ 2562{
2485 const struct fib_trie_iter *iter = seq->private;
2486 struct leaf *l = v; 2563 struct leaf *l = v;
2487 struct leaf_info *li; 2564 struct leaf_info *li;
2488 struct hlist_node *node; 2565 struct hlist_node *node;
@@ -2494,12 +2571,6 @@ static int fib_route_seq_show(struct seq_file *seq, void *v)
2494 return 0; 2571 return 0;
2495 } 2572 }
2496 2573
2497 if (iter->trie == iter->trie_local)
2498 return 0;
2499
2500 if (IS_TNODE(l))
2501 return 0;
2502
2503 hlist_for_each_entry_rcu(li, node, &l->list, hlist) { 2574 hlist_for_each_entry_rcu(li, node, &l->list, hlist) {
2504 struct fib_alias *fa; 2575 struct fib_alias *fa;
2505 __be32 mask, prefix; 2576 __be32 mask, prefix;
@@ -2542,16 +2613,16 @@ static int fib_route_seq_show(struct seq_file *seq, void *v)
2542} 2613}
2543 2614
2544static const struct seq_operations fib_route_seq_ops = { 2615static const struct seq_operations fib_route_seq_ops = {
2545 .start = fib_trie_seq_start, 2616 .start = fib_route_seq_start,
2546 .next = fib_trie_seq_next, 2617 .next = fib_route_seq_next,
2547 .stop = fib_trie_seq_stop, 2618 .stop = fib_route_seq_stop,
2548 .show = fib_route_seq_show, 2619 .show = fib_route_seq_show,
2549}; 2620};
2550 2621
2551static int fib_route_seq_open(struct inode *inode, struct file *file) 2622static int fib_route_seq_open(struct inode *inode, struct file *file)
2552{ 2623{
2553 return seq_open_net(inode, file, &fib_route_seq_ops, 2624 return seq_open_net(inode, file, &fib_route_seq_ops,
2554 sizeof(struct fib_trie_iter)); 2625 sizeof(struct fib_route_iter));
2555} 2626}
2556 2627
2557static const struct file_operations fib_route_fops = { 2628static const struct file_operations fib_route_fops = {