diff options
author | Stephen Hemminger <shemminger@vyatta.com> | 2008-02-12 00:14:39 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-02-12 20:53:31 -0500 |
commit | 8315f5d80a90247bf92232f92ca49933ac49327b (patch) | |
tree | 690332d077339b2d0c93280f08f6fbe9f5b371c7 /net | |
parent | ec28cf738d899e9d0652108e1986101771aacb2e (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>
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv4/fib_trie.c | 93 |
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 | ||
2462 | struct fib_route_iter { | ||
2463 | struct seq_net_private p; | ||
2464 | struct trie *main_trie; | ||
2465 | loff_t pos; | ||
2466 | t_key key; | ||
2467 | }; | ||
2468 | |||
2469 | static 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 | |||
2495 | static 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 | |||
2513 | static 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 | |||
2534 | static void fib_route_seq_stop(struct seq_file *seq, void *v) | ||
2535 | __releases(RCU) | ||
2536 | { | ||
2537 | rcu_read_unlock(); | ||
2538 | } | ||
2539 | |||
2462 | static unsigned fib_flag_trans(int type, __be32 mask, const struct fib_info *fi) | 2540 | static 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 | */ |
2483 | static int fib_route_seq_show(struct seq_file *seq, void *v) | 2561 | static 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 | ||
2544 | static const struct seq_operations fib_route_seq_ops = { | 2615 | static 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 | ||
2551 | static int fib_route_seq_open(struct inode *inode, struct file *file) | 2622 | static 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 | ||
2557 | static const struct file_operations fib_route_fops = { | 2628 | static const struct file_operations fib_route_fops = { |