aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/fib_trie.c
diff options
context:
space:
mode:
authorStephen Hemminger <stephen.hemminger@vyatta.com>2008-01-23 00:57:22 -0500
committerDavid S. Miller <davem@davemloft.net>2008-01-28 18:11:01 -0500
commitd5ce8a0e97073169b5fe0b7c52bd020cdb017dfa (patch)
tree75784ea0b512945ecbcba8f198ece57aa219c412 /net/ipv4/fib_trie.c
parent9195bef7fb0ba0a91d5ffa566bcf8e007e3c7172 (diff)
[IPV4] fib_trie: avoid rescan on dump
This converts dumping (and flushing) of large route tables form O(N^2) to O(N). If the route dump took multiple pages then the dump routine gets called again. The old code kept track of location by counter, the new code instead uses the last key. This is a really big win ( 0.3 sec vs 12 sec) for big route tables. One side effect is that if the table changes during the dump, then the last key will not be found, and we will return -EBUSY. 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.c34
1 files changed, 21 insertions, 13 deletions
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index 441c4eafb9e0..f1005fe17898 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -1917,35 +1917,43 @@ static int fn_trie_dump_leaf(struct leaf *l, struct fib_table *tb,
1917 return skb->len; 1917 return skb->len;
1918} 1918}
1919 1919
1920
1921
1922static int fn_trie_dump(struct fib_table *tb, struct sk_buff *skb, 1920static int fn_trie_dump(struct fib_table *tb, struct sk_buff *skb,
1923 struct netlink_callback *cb) 1921 struct netlink_callback *cb)
1924{ 1922{
1925 struct leaf *l; 1923 struct leaf *l;
1926 struct trie *t = (struct trie *) tb->tb_data; 1924 struct trie *t = (struct trie *) tb->tb_data;
1927 int h = 0; 1925 t_key key = cb->args[2];
1928 int s_h = cb->args[2];
1929 1926
1930 rcu_read_lock(); 1927 rcu_read_lock();
1931 for (h = 0, l = trie_firstleaf(t); l != NULL; h++, l = trie_nextleaf(l)) { 1928 /* Dump starting at last key.
1932 if (h < s_h) 1929 * Note: 0.0.0.0/0 (ie default) is first key.
1933 continue; 1930 */
1934 1931 if (!key)
1935 if (h > s_h) { 1932 l = trie_firstleaf(t);
1936 cb->args[3] = 0; 1933 else {
1937 cb->args[4] = 0; 1934 l = fib_find_node(t, key);
1935 if (!l) {
1936 /* The table changed during the dump, rather than
1937 * giving partial data, just make application retry.
1938 */
1939 rcu_read_unlock();
1940 return -EBUSY;
1938 } 1941 }
1942 }
1939 1943
1944 while (l) {
1945 cb->args[2] = l->key;
1940 if (fn_trie_dump_leaf(l, tb, skb, cb) < 0) { 1946 if (fn_trie_dump_leaf(l, tb, skb, cb) < 0) {
1941 rcu_read_unlock(); 1947 rcu_read_unlock();
1942 cb->args[2] = h;
1943 return -1; 1948 return -1;
1944 } 1949 }
1950
1951 l = trie_nextleaf(l);
1952 memset(&cb->args[3], 0,
1953 sizeof(cb->args) - 3*sizeof(cb->args[0]));
1945 } 1954 }
1946 rcu_read_unlock(); 1955 rcu_read_unlock();
1947 1956
1948 cb->args[2] = h;
1949 return skb->len; 1957 return skb->len;
1950} 1958}
1951 1959