diff options
Diffstat (limited to 'net/ipv4/fib_trie.c')
-rw-r--r-- | net/ipv4/fib_trie.c | 179 |
1 files changed, 95 insertions, 84 deletions
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index 1ff446d0fa8b..a7d089eb042e 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c | |||
@@ -2026,9 +2026,8 @@ struct fib_table *fib_hash_table(u32 id) | |||
2026 | /* Depth first Trie walk iterator */ | 2026 | /* Depth first Trie walk iterator */ |
2027 | struct fib_trie_iter { | 2027 | struct fib_trie_iter { |
2028 | struct seq_net_private p; | 2028 | struct seq_net_private p; |
2029 | struct trie *trie_local, *trie_main; | 2029 | struct fib_table *tb; |
2030 | struct tnode *tnode; | 2030 | struct tnode *tnode; |
2031 | struct trie *trie; | ||
2032 | unsigned index; | 2031 | unsigned index; |
2033 | unsigned depth; | 2032 | unsigned depth; |
2034 | }; | 2033 | }; |
@@ -2081,31 +2080,26 @@ rescan: | |||
2081 | static struct node *fib_trie_get_first(struct fib_trie_iter *iter, | 2080 | static struct node *fib_trie_get_first(struct fib_trie_iter *iter, |
2082 | struct trie *t) | 2081 | struct trie *t) |
2083 | { | 2082 | { |
2084 | struct node *n ; | 2083 | struct node *n; |
2085 | 2084 | ||
2086 | if (!t) | 2085 | if (!t) |
2087 | return NULL; | 2086 | return NULL; |
2088 | 2087 | ||
2089 | n = rcu_dereference(t->trie); | 2088 | n = rcu_dereference(t->trie); |
2090 | 2089 | if (!n) | |
2091 | if (!iter) | ||
2092 | return NULL; | 2090 | return NULL; |
2093 | 2091 | ||
2094 | if (n) { | 2092 | if (IS_TNODE(n)) { |
2095 | if (IS_TNODE(n)) { | 2093 | iter->tnode = (struct tnode *) n; |
2096 | iter->tnode = (struct tnode *) n; | 2094 | iter->index = 0; |
2097 | iter->trie = t; | 2095 | iter->depth = 1; |
2098 | iter->index = 0; | 2096 | } else { |
2099 | iter->depth = 1; | 2097 | iter->tnode = NULL; |
2100 | } else { | 2098 | iter->index = 0; |
2101 | iter->tnode = NULL; | 2099 | iter->depth = 0; |
2102 | iter->trie = t; | ||
2103 | iter->index = 0; | ||
2104 | iter->depth = 0; | ||
2105 | } | ||
2106 | return n; | ||
2107 | } | 2100 | } |
2108 | return NULL; | 2101 | |
2102 | return n; | ||
2109 | } | 2103 | } |
2110 | 2104 | ||
2111 | static void trie_collect_stats(struct trie *t, struct trie_stat *s) | 2105 | static void trie_collect_stats(struct trie *t, struct trie_stat *s) |
@@ -2116,8 +2110,7 @@ static void trie_collect_stats(struct trie *t, struct trie_stat *s) | |||
2116 | memset(s, 0, sizeof(*s)); | 2110 | memset(s, 0, sizeof(*s)); |
2117 | 2111 | ||
2118 | rcu_read_lock(); | 2112 | rcu_read_lock(); |
2119 | for (n = fib_trie_get_first(&iter, t); n; | 2113 | for (n = fib_trie_get_first(&iter, t); n; n = fib_trie_get_next(&iter)) { |
2120 | n = fib_trie_get_next(&iter)) { | ||
2121 | if (IS_LEAF(n)) { | 2114 | if (IS_LEAF(n)) { |
2122 | struct leaf *l = (struct leaf *)n; | 2115 | struct leaf *l = (struct leaf *)n; |
2123 | struct leaf_info *li; | 2116 | struct leaf_info *li; |
@@ -2206,36 +2199,48 @@ static void trie_show_usage(struct seq_file *seq, | |||
2206 | } | 2199 | } |
2207 | #endif /* CONFIG_IP_FIB_TRIE_STATS */ | 2200 | #endif /* CONFIG_IP_FIB_TRIE_STATS */ |
2208 | 2201 | ||
2209 | static void fib_trie_show(struct seq_file *seq, const char *name, | 2202 | static void fib_table_print(struct seq_file *seq, struct fib_table *tb) |
2210 | struct trie *trie) | ||
2211 | { | 2203 | { |
2212 | struct trie_stat stat; | 2204 | if (tb->tb_id == RT_TABLE_LOCAL) |
2213 | 2205 | seq_puts(seq, "Local:\n"); | |
2214 | trie_collect_stats(trie, &stat); | 2206 | else if (tb->tb_id == RT_TABLE_MAIN) |
2215 | seq_printf(seq, "%s:\n", name); | 2207 | seq_puts(seq, "Main:\n"); |
2216 | trie_show_stats(seq, &stat); | 2208 | else |
2217 | #ifdef CONFIG_IP_FIB_TRIE_STATS | 2209 | seq_printf(seq, "Id %d:\n", tb->tb_id); |
2218 | trie_show_usage(seq, &trie->stats); | ||
2219 | #endif | ||
2220 | } | 2210 | } |
2221 | 2211 | ||
2212 | |||
2222 | static int fib_triestat_seq_show(struct seq_file *seq, void *v) | 2213 | static int fib_triestat_seq_show(struct seq_file *seq, void *v) |
2223 | { | 2214 | { |
2224 | struct net *net = (struct net *)seq->private; | 2215 | struct net *net = (struct net *)seq->private; |
2225 | struct fib_table *tb; | 2216 | unsigned int h; |
2226 | 2217 | ||
2227 | seq_printf(seq, | 2218 | seq_printf(seq, |
2228 | "Basic info: size of leaf:" | 2219 | "Basic info: size of leaf:" |
2229 | " %Zd bytes, size of tnode: %Zd bytes.\n", | 2220 | " %Zd bytes, size of tnode: %Zd bytes.\n", |
2230 | sizeof(struct leaf), sizeof(struct tnode)); | 2221 | sizeof(struct leaf), sizeof(struct tnode)); |
2231 | 2222 | ||
2232 | tb = fib_get_table(net, RT_TABLE_LOCAL); | 2223 | for (h = 0; h < FIB_TABLE_HASHSZ; h++) { |
2233 | if (tb) | 2224 | struct hlist_head *head = &net->ipv4.fib_table_hash[h]; |
2234 | fib_trie_show(seq, "Local", (struct trie *) tb->tb_data); | 2225 | struct hlist_node *node; |
2226 | struct fib_table *tb; | ||
2227 | |||
2228 | hlist_for_each_entry_rcu(tb, node, head, tb_hlist) { | ||
2229 | struct trie *t = (struct trie *) tb->tb_data; | ||
2230 | struct trie_stat stat; | ||
2231 | |||
2232 | if (!t) | ||
2233 | continue; | ||
2235 | 2234 | ||
2236 | tb = fib_get_table(net, RT_TABLE_MAIN); | 2235 | fib_table_print(seq, tb); |
2237 | if (tb) | 2236 | |
2238 | fib_trie_show(seq, "Main", (struct trie *) tb->tb_data); | 2237 | trie_collect_stats(t, &stat); |
2238 | trie_show_stats(seq, &stat); | ||
2239 | #ifdef CONFIG_IP_FIB_TRIE_STATS | ||
2240 | trie_show_usage(seq, &t->stats); | ||
2241 | #endif | ||
2242 | } | ||
2243 | } | ||
2239 | 2244 | ||
2240 | return 0; | 2245 | return 0; |
2241 | } | 2246 | } |
@@ -2271,23 +2276,30 @@ static const struct file_operations fib_triestat_fops = { | |||
2271 | .release = fib_triestat_seq_release, | 2276 | .release = fib_triestat_seq_release, |
2272 | }; | 2277 | }; |
2273 | 2278 | ||
2274 | static struct node *fib_trie_get_idx(struct fib_trie_iter *iter, | 2279 | static struct node *fib_trie_get_idx(struct fib_trie_iter *iter, loff_t pos) |
2275 | loff_t pos) | ||
2276 | { | 2280 | { |
2281 | struct net *net = iter->p.net; | ||
2277 | loff_t idx = 0; | 2282 | loff_t idx = 0; |
2278 | struct node *n; | 2283 | unsigned int h; |
2279 | 2284 | ||
2280 | for (n = fib_trie_get_first(iter, iter->trie_local); | 2285 | for (h = 0; h < FIB_TABLE_HASHSZ; h++) { |
2281 | n; ++idx, n = fib_trie_get_next(iter)) { | 2286 | struct hlist_head *head = &net->ipv4.fib_table_hash[h]; |
2282 | if (pos == idx) | 2287 | struct hlist_node *node; |
2283 | return n; | 2288 | struct fib_table *tb; |
2284 | } | ||
2285 | 2289 | ||
2286 | for (n = fib_trie_get_first(iter, iter->trie_main); | 2290 | hlist_for_each_entry_rcu(tb, node, head, tb_hlist) { |
2287 | n; ++idx, n = fib_trie_get_next(iter)) { | 2291 | struct node *n; |
2288 | if (pos == idx) | 2292 | |
2289 | return n; | 2293 | for (n = fib_trie_get_first(iter, |
2294 | (struct trie *) tb->tb_data); | ||
2295 | n; n = fib_trie_get_next(iter)) | ||
2296 | if (pos == idx++) { | ||
2297 | iter->tb = tb; | ||
2298 | return n; | ||
2299 | } | ||
2300 | } | ||
2290 | } | 2301 | } |
2302 | |||
2291 | return NULL; | 2303 | return NULL; |
2292 | } | 2304 | } |
2293 | 2305 | ||
@@ -2295,43 +2307,49 @@ static void *fib_trie_seq_start(struct seq_file *seq, loff_t *pos) | |||
2295 | __acquires(RCU) | 2307 | __acquires(RCU) |
2296 | { | 2308 | { |
2297 | struct fib_trie_iter *iter = seq->private; | 2309 | struct fib_trie_iter *iter = seq->private; |
2298 | struct fib_table *tb; | ||
2299 | 2310 | ||
2300 | if (!iter->trie_local) { | ||
2301 | tb = fib_get_table(iter->p.net, RT_TABLE_LOCAL); | ||
2302 | if (tb) | ||
2303 | iter->trie_local = (struct trie *) tb->tb_data; | ||
2304 | } | ||
2305 | if (!iter->trie_main) { | ||
2306 | tb = fib_get_table(iter->p.net, RT_TABLE_MAIN); | ||
2307 | if (tb) | ||
2308 | iter->trie_main = (struct trie *) tb->tb_data; | ||
2309 | } | ||
2310 | rcu_read_lock(); | 2311 | rcu_read_lock(); |
2311 | if (*pos == 0) | 2312 | return fib_trie_get_idx(iter, *pos); |
2312 | return SEQ_START_TOKEN; | ||
2313 | return fib_trie_get_idx(iter, *pos - 1); | ||
2314 | } | 2313 | } |
2315 | 2314 | ||
2316 | static void *fib_trie_seq_next(struct seq_file *seq, void *v, loff_t *pos) | 2315 | static void *fib_trie_seq_next(struct seq_file *seq, void *v, loff_t *pos) |
2317 | { | 2316 | { |
2318 | struct fib_trie_iter *iter = seq->private; | 2317 | struct fib_trie_iter *iter = seq->private; |
2319 | void *l = v; | 2318 | struct net *net = iter->p.net; |
2319 | struct fib_table *tb = iter->tb; | ||
2320 | struct hlist_node *tb_node; | ||
2321 | unsigned int h; | ||
2322 | struct node *n; | ||
2320 | 2323 | ||
2321 | ++*pos; | 2324 | ++*pos; |
2322 | if (v == SEQ_START_TOKEN) | 2325 | /* next node in same table */ |
2323 | return fib_trie_get_idx(iter, 0); | 2326 | n = fib_trie_get_next(iter); |
2324 | 2327 | if (n) | |
2325 | v = fib_trie_get_next(iter); | 2328 | return n; |
2326 | BUG_ON(v == l); | ||
2327 | if (v) | ||
2328 | return v; | ||
2329 | 2329 | ||
2330 | /* continue scan in next trie */ | 2330 | /* walk rest of this hash chain */ |
2331 | if (iter->trie == iter->trie_local) | 2331 | h = tb->tb_id & (FIB_TABLE_HASHSZ - 1); |
2332 | return fib_trie_get_first(iter, iter->trie_main); | 2332 | while ( (tb_node = rcu_dereference(tb->tb_hlist.next)) ) { |
2333 | tb = hlist_entry(tb_node, struct fib_table, tb_hlist); | ||
2334 | n = fib_trie_get_first(iter, (struct trie *) tb->tb_data); | ||
2335 | if (n) | ||
2336 | goto found; | ||
2337 | } | ||
2333 | 2338 | ||
2339 | /* new hash chain */ | ||
2340 | while (++h < FIB_TABLE_HASHSZ) { | ||
2341 | struct hlist_head *head = &net->ipv4.fib_table_hash[h]; | ||
2342 | hlist_for_each_entry_rcu(tb, tb_node, head, tb_hlist) { | ||
2343 | n = fib_trie_get_first(iter, (struct trie *) tb->tb_data); | ||
2344 | if (n) | ||
2345 | goto found; | ||
2346 | } | ||
2347 | } | ||
2334 | return NULL; | 2348 | return NULL; |
2349 | |||
2350 | found: | ||
2351 | iter->tb = tb; | ||
2352 | return n; | ||
2335 | } | 2353 | } |
2336 | 2354 | ||
2337 | static void fib_trie_seq_stop(struct seq_file *seq, void *v) | 2355 | static void fib_trie_seq_stop(struct seq_file *seq, void *v) |
@@ -2388,15 +2406,8 @@ static int fib_trie_seq_show(struct seq_file *seq, void *v) | |||
2388 | const struct fib_trie_iter *iter = seq->private; | 2406 | const struct fib_trie_iter *iter = seq->private; |
2389 | struct node *n = v; | 2407 | struct node *n = v; |
2390 | 2408 | ||
2391 | if (v == SEQ_START_TOKEN) | 2409 | if (!node_parent_rcu(n)) |
2392 | return 0; | 2410 | fib_table_print(seq, iter->tb); |
2393 | |||
2394 | if (!node_parent_rcu(n)) { | ||
2395 | if (iter->trie == iter->trie_local) | ||
2396 | seq_puts(seq, "<local>:\n"); | ||
2397 | else | ||
2398 | seq_puts(seq, "<main>:\n"); | ||
2399 | } | ||
2400 | 2411 | ||
2401 | if (IS_TNODE(n)) { | 2412 | if (IS_TNODE(n)) { |
2402 | struct tnode *tn = (struct tnode *) n; | 2413 | struct tnode *tn = (struct tnode *) n; |