aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4')
-rw-r--r--net/ipv4/fib_trie.c179
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 */
2027struct fib_trie_iter { 2027struct 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:
2081static struct node *fib_trie_get_first(struct fib_trie_iter *iter, 2080static 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
2111static void trie_collect_stats(struct trie *t, struct trie_stat *s) 2105static 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
2209static void fib_trie_show(struct seq_file *seq, const char *name, 2202static 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
2222static int fib_triestat_seq_show(struct seq_file *seq, void *v) 2213static 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
2274static struct node *fib_trie_get_idx(struct fib_trie_iter *iter, 2279static 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
2316static void *fib_trie_seq_next(struct seq_file *seq, void *v, loff_t *pos) 2315static 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
2350found:
2351 iter->tb = tb;
2352 return n;
2335} 2353}
2336 2354
2337static void fib_trie_seq_stop(struct seq_file *seq, void *v) 2355static 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;