aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/fib_trie.c
diff options
context:
space:
mode:
authorStephen Hemminger <stephen.hemminger@vyatta.com>2008-01-23 00:55:32 -0500
committerDavid S. Miller <davem@davemloft.net>2008-01-28 18:10:59 -0500
commit82cfbb008572b1a953091ef78f767aa3ca213092 (patch)
tree1e2ef11b188e89dd41b28b20580b2c424d75e9bd /net/ipv4/fib_trie.c
parent64347f786d13349d6a6f812f3a83c269e26c0136 (diff)
[IPV4] fib_trie: iterator recode
Remove the complex loop structure of nextleaf() and replace it with a simpler tree walker. This improves the performance and is much cleaner. Signed-off-by: Stephen Hemminger <shemminger@vyatta.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/fib_trie.c')
-rw-r--r--net/ipv4/fib_trie.c103
1 files changed, 52 insertions, 51 deletions
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index 41264695039a..dab439b52672 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -1711,64 +1711,65 @@ static int trie_flush_leaf(struct trie *t, struct leaf *l)
1711 return found; 1711 return found;
1712} 1712}
1713 1713
1714/* rcu_read_lock needs to be hold by caller from readside */ 1714/*
1715 1715 * Scan for the next right leaf starting at node p->child[idx]
1716static struct leaf *nextleaf(struct trie *t, struct leaf *thisleaf) 1716 * Since we have back pointer, no recursion necessary.
1717 */
1718static struct leaf *leaf_walk_rcu(struct tnode *p, struct node *c)
1717{ 1719{
1718 struct node *c = (struct node *) thisleaf; 1720 do {
1719 struct tnode *p; 1721 t_key idx;
1720 int idx;
1721 struct node *trie = rcu_dereference(t->trie);
1722 1722
1723 if (c == NULL) {
1724 if (trie == NULL)
1725 return NULL;
1726
1727 if (IS_LEAF(trie)) /* trie w. just a leaf */
1728 return (struct leaf *) trie;
1729
1730 p = (struct tnode *)trie; /* Start */
1731 } else
1732 p = node_parent_rcu(c);
1733
1734 while (p) {
1735 int pos, last;
1736
1737 /* Find the next child of the parent */
1738 if (c) 1723 if (c)
1739 pos = 1 + tkey_extract_bits(c->key, p->pos, p->bits); 1724 idx = tkey_extract_bits(c->key, p->pos, p->bits) + 1;
1740 else 1725 else
1741 pos = 0; 1726 idx = 0;
1742
1743 last = 1 << p->bits;
1744 for (idx = pos; idx < last ; idx++) {
1745 c = rcu_dereference(p->child[idx]);
1746 1727
1728 while (idx < 1u << p->bits) {
1729 c = tnode_get_child_rcu(p, idx++);
1747 if (!c) 1730 if (!c)
1748 continue; 1731 continue;
1749 1732
1750 /* Decend if tnode */ 1733 if (IS_LEAF(c)) {
1751 while (IS_TNODE(c)) { 1734 prefetch(p->child[idx]);
1752 p = (struct tnode *) c; 1735 return (struct leaf *) c;
1753 idx = 0;
1754
1755 /* Rightmost non-NULL branch */
1756 if (p && IS_TNODE(p))
1757 while (!(c = rcu_dereference(p->child[idx]))
1758 && idx < (1<<p->bits)) idx++;
1759
1760 /* Done with this tnode? */
1761 if (idx >= (1 << p->bits) || !c)
1762 goto up;
1763 } 1736 }
1764 return (struct leaf *) c; 1737
1738 /* Rescan start scanning in new node */
1739 p = (struct tnode *) c;
1740 idx = 0;
1765 } 1741 }
1766up: 1742
1767 /* No more children go up one step */ 1743 /* Node empty, walk back up to parent */
1768 c = (struct node *) p; 1744 c = (struct node *) p;
1769 p = node_parent_rcu(c); 1745 } while ( (p = node_parent_rcu(c)) != NULL);
1770 } 1746
1771 return NULL; /* Ready. Root of trie */ 1747 return NULL; /* Root of trie */
1748}
1749
1750
1751static struct leaf *trie_firstleaf(struct trie *t)
1752{
1753 struct tnode *n = (struct tnode *) rcu_dereference(t->trie);
1754
1755 if (!n)
1756 return NULL;
1757
1758 if (IS_LEAF(n)) /* trie is just a leaf */
1759 return (struct leaf *) n;
1760
1761 return leaf_walk_rcu(n, NULL);
1762}
1763
1764static struct leaf *trie_nextleaf(struct leaf *l)
1765{
1766 struct node *c = (struct node *) l;
1767 struct tnode *p = node_parent(c);
1768
1769 if (!p)
1770 return NULL; /* trie with just one leaf */
1771
1772 return leaf_walk_rcu(p, c);
1772} 1773}
1773 1774
1774/* 1775/*
@@ -1778,9 +1779,9 @@ static int fn_trie_flush(struct fib_table *tb)
1778{ 1779{
1779 struct trie *t = (struct trie *) tb->tb_data; 1780 struct trie *t = (struct trie *) tb->tb_data;
1780 struct leaf *ll = NULL, *l = NULL; 1781 struct leaf *ll = NULL, *l = NULL;
1781 int found = 0, h; 1782 int found = 0;
1782 1783
1783 for (h = 0; (l = nextleaf(t, l)) != NULL; h++) { 1784 for (l = trie_firstleaf(t); l; l = trie_nextleaf(l)) {
1784 found += trie_flush_leaf(t, l); 1785 found += trie_flush_leaf(t, l);
1785 1786
1786 if (ll && hlist_empty(&ll->list)) 1787 if (ll && hlist_empty(&ll->list))
@@ -1887,7 +1888,6 @@ static int fn_trie_dump_fa(t_key key, int plen, struct list_head *fah,
1887 i++; 1888 i++;
1888 continue; 1889 continue;
1889 } 1890 }
1890 BUG_ON(!fa->fa_info);
1891 1891
1892 if (fib_dump_info(skb, NETLINK_CB(cb->skb).pid, 1892 if (fib_dump_info(skb, NETLINK_CB(cb->skb).pid,
1893 cb->nlh->nlmsg_seq, 1893 cb->nlh->nlmsg_seq,
@@ -1916,8 +1916,9 @@ static int fn_trie_dump_plen(struct trie *t, int plen, struct fib_table *tb,
1916 struct leaf *l = NULL; 1916 struct leaf *l = NULL;
1917 1917
1918 s_h = cb->args[3]; 1918 s_h = cb->args[3];
1919 h = 0;
1919 1920
1920 for (h = 0; (l = nextleaf(t, l)) != NULL; h++) { 1921 for (l = trie_firstleaf(t); l != NULL; h++, l = trie_nextleaf(l)) {
1921 if (h < s_h) 1922 if (h < s_h)
1922 continue; 1923 continue;
1923 if (h > s_h) 1924 if (h > s_h)