diff options
Diffstat (limited to 'net/ipv4/fib_trie.c')
-rw-r--r-- | net/ipv4/fib_trie.c | 74 |
1 files changed, 39 insertions, 35 deletions
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index dab439b52672..2ea94ebe19f8 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c | |||
@@ -1908,67 +1908,71 @@ static int fn_trie_dump_fa(t_key key, int plen, struct list_head *fah, | |||
1908 | return skb->len; | 1908 | return skb->len; |
1909 | } | 1909 | } |
1910 | 1910 | ||
1911 | static int fn_trie_dump_plen(struct trie *t, int plen, struct fib_table *tb, | 1911 | |
1912 | struct sk_buff *skb, struct netlink_callback *cb) | 1912 | static int fn_trie_dump_leaf(struct leaf *l, struct fib_table *tb, |
1913 | struct sk_buff *skb, struct netlink_callback *cb) | ||
1913 | { | 1914 | { |
1914 | int h, s_h; | 1915 | struct leaf_info *li; |
1915 | struct list_head *fa_head; | 1916 | struct hlist_node *node; |
1916 | struct leaf *l = NULL; | 1917 | int i, s_i; |
1917 | 1918 | ||
1918 | s_h = cb->args[3]; | 1919 | s_i = cb->args[3]; |
1919 | h = 0; | 1920 | i = 0; |
1920 | 1921 | ||
1921 | for (l = trie_firstleaf(t); l != NULL; h++, l = trie_nextleaf(l)) { | 1922 | /* rcu_read_lock is hold by caller */ |
1922 | if (h < s_h) | 1923 | hlist_for_each_entry_rcu(li, node, &l->list, hlist) { |
1924 | if (i < s_i) { | ||
1925 | i++; | ||
1923 | continue; | 1926 | continue; |
1924 | if (h > s_h) | 1927 | } |
1925 | memset(&cb->args[4], 0, | ||
1926 | sizeof(cb->args) - 4*sizeof(cb->args[0])); | ||
1927 | |||
1928 | fa_head = get_fa_head(l, plen); | ||
1929 | 1928 | ||
1930 | if (!fa_head) | 1929 | if (i > s_i) |
1931 | continue; | 1930 | cb->args[4] = 0; |
1932 | 1931 | ||
1933 | if (list_empty(fa_head)) | 1932 | if (list_empty(&li->falh)) |
1934 | continue; | 1933 | continue; |
1935 | 1934 | ||
1936 | if (fn_trie_dump_fa(l->key, plen, fa_head, tb, skb, cb) < 0) { | 1935 | if (fn_trie_dump_fa(l->key, li->plen, &li->falh, tb, skb, cb) < 0) { |
1937 | cb->args[3] = h; | 1936 | cb->args[3] = i; |
1938 | return -1; | 1937 | return -1; |
1939 | } | 1938 | } |
1939 | i++; | ||
1940 | } | 1940 | } |
1941 | cb->args[3] = h; | 1941 | |
1942 | cb->args[3] = i; | ||
1942 | return skb->len; | 1943 | return skb->len; |
1943 | } | 1944 | } |
1944 | 1945 | ||
1946 | |||
1947 | |||
1945 | static int fn_trie_dump(struct fib_table *tb, struct sk_buff *skb, | 1948 | static int fn_trie_dump(struct fib_table *tb, struct sk_buff *skb, |
1946 | struct netlink_callback *cb) | 1949 | struct netlink_callback *cb) |
1947 | { | 1950 | { |
1948 | int m, s_m; | 1951 | struct leaf *l; |
1949 | struct trie *t = (struct trie *) tb->tb_data; | 1952 | struct trie *t = (struct trie *) tb->tb_data; |
1950 | 1953 | int h = 0; | |
1951 | s_m = cb->args[2]; | 1954 | int s_h = cb->args[2]; |
1952 | 1955 | ||
1953 | rcu_read_lock(); | 1956 | rcu_read_lock(); |
1954 | for (m = 0; m <= 32; m++) { | 1957 | for (h = 0, l = trie_firstleaf(t); l != NULL; h++, l = trie_nextleaf(l)) { |
1955 | if (m < s_m) | 1958 | if (h < s_h) |
1956 | continue; | 1959 | continue; |
1957 | if (m > s_m) | ||
1958 | memset(&cb->args[3], 0, | ||
1959 | sizeof(cb->args) - 3*sizeof(cb->args[0])); | ||
1960 | 1960 | ||
1961 | if (fn_trie_dump_plen(t, 32-m, tb, skb, cb) < 0) { | 1961 | if (h > s_h) { |
1962 | cb->args[2] = m; | 1962 | cb->args[3] = 0; |
1963 | goto out; | 1963 | cb->args[4] = 0; |
1964 | } | ||
1965 | |||
1966 | if (fn_trie_dump_leaf(l, tb, skb, cb) < 0) { | ||
1967 | rcu_read_unlock(); | ||
1968 | cb->args[2] = h; | ||
1969 | return -1; | ||
1964 | } | 1970 | } |
1965 | } | 1971 | } |
1966 | rcu_read_unlock(); | 1972 | rcu_read_unlock(); |
1967 | cb->args[2] = m; | 1973 | |
1974 | cb->args[2] = h; | ||
1968 | return skb->len; | 1975 | return skb->len; |
1969 | out: | ||
1970 | rcu_read_unlock(); | ||
1971 | return -1; | ||
1972 | } | 1976 | } |
1973 | 1977 | ||
1974 | void __init fib_hash_init(void) | 1978 | void __init fib_hash_init(void) |