aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/fib_trie.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4/fib_trie.c')
-rw-r--r--net/ipv4/fib_trie.c240
1 files changed, 129 insertions, 111 deletions
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index f6cdc012eec5..ea294fffb9ce 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -122,7 +122,10 @@ struct tnode {
122 unsigned char bits; /* 2log(KEYLENGTH) bits needed */ 122 unsigned char bits; /* 2log(KEYLENGTH) bits needed */
123 unsigned int full_children; /* KEYLENGTH bits needed */ 123 unsigned int full_children; /* KEYLENGTH bits needed */
124 unsigned int empty_children; /* KEYLENGTH bits needed */ 124 unsigned int empty_children; /* KEYLENGTH bits needed */
125 struct rcu_head rcu; 125 union {
126 struct rcu_head rcu;
127 struct work_struct work;
128 };
126 struct node *child[0]; 129 struct node *child[0];
127}; 130};
128 131
@@ -160,7 +163,6 @@ static void tnode_put_child_reorg(struct tnode *tn, int i, struct node *n,
160static struct node *resize(struct trie *t, struct tnode *tn); 163static struct node *resize(struct trie *t, struct tnode *tn);
161static struct tnode *inflate(struct trie *t, struct tnode *tn); 164static struct tnode *inflate(struct trie *t, struct tnode *tn);
162static struct tnode *halve(struct trie *t, struct tnode *tn); 165static struct tnode *halve(struct trie *t, struct tnode *tn);
163static void tnode_free(struct tnode *tn);
164 166
165static struct kmem_cache *fn_alias_kmem __read_mostly; 167static struct kmem_cache *fn_alias_kmem __read_mostly;
166static struct kmem_cache *trie_leaf_kmem __read_mostly; 168static struct kmem_cache *trie_leaf_kmem __read_mostly;
@@ -334,6 +336,11 @@ static void __leaf_free_rcu(struct rcu_head *head)
334 kmem_cache_free(trie_leaf_kmem, l); 336 kmem_cache_free(trie_leaf_kmem, l);
335} 337}
336 338
339static inline void free_leaf(struct leaf *l)
340{
341 call_rcu_bh(&l->rcu, __leaf_free_rcu);
342}
343
337static void __leaf_info_free_rcu(struct rcu_head *head) 344static void __leaf_info_free_rcu(struct rcu_head *head)
338{ 345{
339 kfree(container_of(head, struct leaf_info, rcu)); 346 kfree(container_of(head, struct leaf_info, rcu));
@@ -346,16 +353,16 @@ static inline void free_leaf_info(struct leaf_info *leaf)
346 353
347static struct tnode *tnode_alloc(size_t size) 354static struct tnode *tnode_alloc(size_t size)
348{ 355{
349 struct page *pages;
350
351 if (size <= PAGE_SIZE) 356 if (size <= PAGE_SIZE)
352 return kzalloc(size, GFP_KERNEL); 357 return kzalloc(size, GFP_KERNEL);
358 else
359 return __vmalloc(size, GFP_KERNEL | __GFP_ZERO, PAGE_KERNEL);
360}
353 361
354 pages = alloc_pages(GFP_KERNEL|__GFP_ZERO, get_order(size)); 362static void __tnode_vfree(struct work_struct *arg)
355 if (!pages) 363{
356 return NULL; 364 struct tnode *tn = container_of(arg, struct tnode, work);
357 365 vfree(tn);
358 return page_address(pages);
359} 366}
360 367
361static void __tnode_free_rcu(struct rcu_head *head) 368static void __tnode_free_rcu(struct rcu_head *head)
@@ -366,16 +373,17 @@ static void __tnode_free_rcu(struct rcu_head *head)
366 373
367 if (size <= PAGE_SIZE) 374 if (size <= PAGE_SIZE)
368 kfree(tn); 375 kfree(tn);
369 else 376 else {
370 free_pages((unsigned long)tn, get_order(size)); 377 INIT_WORK(&tn->work, __tnode_vfree);
378 schedule_work(&tn->work);
379 }
371} 380}
372 381
373static inline void tnode_free(struct tnode *tn) 382static inline void tnode_free(struct tnode *tn)
374{ 383{
375 if (IS_LEAF(tn)) { 384 if (IS_LEAF(tn))
376 struct leaf *l = (struct leaf *) tn; 385 free_leaf((struct leaf *) tn);
377 call_rcu_bh(&l->rcu, __leaf_free_rcu); 386 else
378 } else
379 call_rcu(&tn->rcu, __tnode_free_rcu); 387 call_rcu(&tn->rcu, __tnode_free_rcu);
380} 388}
381 389
@@ -1086,7 +1094,7 @@ static struct list_head *fib_insert_node(struct trie *t, u32 key, int plen)
1086 li = leaf_info_new(plen); 1094 li = leaf_info_new(plen);
1087 1095
1088 if (!li) { 1096 if (!li) {
1089 tnode_free((struct tnode *) l); 1097 free_leaf(l);
1090 return NULL; 1098 return NULL;
1091 } 1099 }
1092 1100
@@ -1122,7 +1130,7 @@ static struct list_head *fib_insert_node(struct trie *t, u32 key, int plen)
1122 1130
1123 if (!tn) { 1131 if (!tn) {
1124 free_leaf_info(li); 1132 free_leaf_info(li);
1125 tnode_free((struct tnode *) l); 1133 free_leaf(l);
1126 return NULL; 1134 return NULL;
1127 } 1135 }
1128 1136
@@ -1578,7 +1586,7 @@ static void trie_leaf_remove(struct trie *t, struct leaf *l)
1578 } else 1586 } else
1579 rcu_assign_pointer(t->trie, NULL); 1587 rcu_assign_pointer(t->trie, NULL);
1580 1588
1581 tnode_free((struct tnode *) l); 1589 free_leaf(l);
1582} 1590}
1583 1591
1584/* 1592/*
@@ -1665,7 +1673,7 @@ static int fn_trie_delete(struct fib_table *tb, struct fib_config *cfg)
1665 return 0; 1673 return 0;
1666} 1674}
1667 1675
1668static int trie_flush_list(struct trie *t, struct list_head *head) 1676static int trie_flush_list(struct list_head *head)
1669{ 1677{
1670 struct fib_alias *fa, *fa_node; 1678 struct fib_alias *fa, *fa_node;
1671 int found = 0; 1679 int found = 0;
@@ -1683,7 +1691,7 @@ static int trie_flush_list(struct trie *t, struct list_head *head)
1683 return found; 1691 return found;
1684} 1692}
1685 1693
1686static int trie_flush_leaf(struct trie *t, struct leaf *l) 1694static int trie_flush_leaf(struct leaf *l)
1687{ 1695{
1688 int found = 0; 1696 int found = 0;
1689 struct hlist_head *lih = &l->list; 1697 struct hlist_head *lih = &l->list;
@@ -1691,7 +1699,7 @@ static int trie_flush_leaf(struct trie *t, struct leaf *l)
1691 struct leaf_info *li = NULL; 1699 struct leaf_info *li = NULL;
1692 1700
1693 hlist_for_each_entry_safe(li, node, tmp, lih, hlist) { 1701 hlist_for_each_entry_safe(li, node, tmp, lih, hlist) {
1694 found += trie_flush_list(t, &li->falh); 1702 found += trie_flush_list(&li->falh);
1695 1703
1696 if (list_empty(&li->falh)) { 1704 if (list_empty(&li->falh)) {
1697 hlist_del_rcu(&li->hlist); 1705 hlist_del_rcu(&li->hlist);
@@ -1782,7 +1790,7 @@ static int fn_trie_flush(struct fib_table *tb)
1782 int found = 0; 1790 int found = 0;
1783 1791
1784 for (l = trie_firstleaf(t); l; l = trie_nextleaf(l)) { 1792 for (l = trie_firstleaf(t); l; l = trie_nextleaf(l)) {
1785 found += trie_flush_leaf(t, l); 1793 found += trie_flush_leaf(l);
1786 1794
1787 if (ll && hlist_empty(&ll->list)) 1795 if (ll && hlist_empty(&ll->list))
1788 trie_leaf_remove(t, ll); 1796 trie_leaf_remove(t, ll);
@@ -2029,9 +2037,8 @@ struct fib_table *fib_hash_table(u32 id)
2029/* Depth first Trie walk iterator */ 2037/* Depth first Trie walk iterator */
2030struct fib_trie_iter { 2038struct fib_trie_iter {
2031 struct seq_net_private p; 2039 struct seq_net_private p;
2032 struct trie *trie_local, *trie_main; 2040 struct fib_table *tb;
2033 struct tnode *tnode; 2041 struct tnode *tnode;
2034 struct trie *trie;
2035 unsigned index; 2042 unsigned index;
2036 unsigned depth; 2043 unsigned depth;
2037}; 2044};
@@ -2084,31 +2091,26 @@ rescan:
2084static struct node *fib_trie_get_first(struct fib_trie_iter *iter, 2091static struct node *fib_trie_get_first(struct fib_trie_iter *iter,
2085 struct trie *t) 2092 struct trie *t)
2086{ 2093{
2087 struct node *n ; 2094 struct node *n;
2088 2095
2089 if (!t) 2096 if (!t)
2090 return NULL; 2097 return NULL;
2091 2098
2092 n = rcu_dereference(t->trie); 2099 n = rcu_dereference(t->trie);
2093 2100 if (!n)
2094 if (!iter)
2095 return NULL; 2101 return NULL;
2096 2102
2097 if (n) { 2103 if (IS_TNODE(n)) {
2098 if (IS_TNODE(n)) { 2104 iter->tnode = (struct tnode *) n;
2099 iter->tnode = (struct tnode *) n; 2105 iter->index = 0;
2100 iter->trie = t; 2106 iter->depth = 1;
2101 iter->index = 0; 2107 } else {
2102 iter->depth = 1; 2108 iter->tnode = NULL;
2103 } else { 2109 iter->index = 0;
2104 iter->tnode = NULL; 2110 iter->depth = 0;
2105 iter->trie = t;
2106 iter->index = 0;
2107 iter->depth = 0;
2108 }
2109 return n;
2110 } 2111 }
2111 return NULL; 2112
2113 return n;
2112} 2114}
2113 2115
2114static void trie_collect_stats(struct trie *t, struct trie_stat *s) 2116static void trie_collect_stats(struct trie *t, struct trie_stat *s)
@@ -2119,8 +2121,7 @@ static void trie_collect_stats(struct trie *t, struct trie_stat *s)
2119 memset(s, 0, sizeof(*s)); 2121 memset(s, 0, sizeof(*s));
2120 2122
2121 rcu_read_lock(); 2123 rcu_read_lock();
2122 for (n = fib_trie_get_first(&iter, t); n; 2124 for (n = fib_trie_get_first(&iter, t); n; n = fib_trie_get_next(&iter)) {
2123 n = fib_trie_get_next(&iter)) {
2124 if (IS_LEAF(n)) { 2125 if (IS_LEAF(n)) {
2125 struct leaf *l = (struct leaf *)n; 2126 struct leaf *l = (struct leaf *)n;
2126 struct leaf_info *li; 2127 struct leaf_info *li;
@@ -2209,36 +2210,48 @@ static void trie_show_usage(struct seq_file *seq,
2209} 2210}
2210#endif /* CONFIG_IP_FIB_TRIE_STATS */ 2211#endif /* CONFIG_IP_FIB_TRIE_STATS */
2211 2212
2212static void fib_trie_show(struct seq_file *seq, const char *name, 2213static void fib_table_print(struct seq_file *seq, struct fib_table *tb)
2213 struct trie *trie)
2214{ 2214{
2215 struct trie_stat stat; 2215 if (tb->tb_id == RT_TABLE_LOCAL)
2216 2216 seq_puts(seq, "Local:\n");
2217 trie_collect_stats(trie, &stat); 2217 else if (tb->tb_id == RT_TABLE_MAIN)
2218 seq_printf(seq, "%s:\n", name); 2218 seq_puts(seq, "Main:\n");
2219 trie_show_stats(seq, &stat); 2219 else
2220#ifdef CONFIG_IP_FIB_TRIE_STATS 2220 seq_printf(seq, "Id %d:\n", tb->tb_id);
2221 trie_show_usage(seq, &trie->stats);
2222#endif
2223} 2221}
2224 2222
2223
2225static int fib_triestat_seq_show(struct seq_file *seq, void *v) 2224static int fib_triestat_seq_show(struct seq_file *seq, void *v)
2226{ 2225{
2227 struct net *net = (struct net *)seq->private; 2226 struct net *net = (struct net *)seq->private;
2228 struct fib_table *tb; 2227 unsigned int h;
2229 2228
2230 seq_printf(seq, 2229 seq_printf(seq,
2231 "Basic info: size of leaf:" 2230 "Basic info: size of leaf:"
2232 " %Zd bytes, size of tnode: %Zd bytes.\n", 2231 " %Zd bytes, size of tnode: %Zd bytes.\n",
2233 sizeof(struct leaf), sizeof(struct tnode)); 2232 sizeof(struct leaf), sizeof(struct tnode));
2234 2233
2235 tb = fib_get_table(net, RT_TABLE_LOCAL); 2234 for (h = 0; h < FIB_TABLE_HASHSZ; h++) {
2236 if (tb) 2235 struct hlist_head *head = &net->ipv4.fib_table_hash[h];
2237 fib_trie_show(seq, "Local", (struct trie *) tb->tb_data); 2236 struct hlist_node *node;
2237 struct fib_table *tb;
2238
2239 hlist_for_each_entry_rcu(tb, node, head, tb_hlist) {
2240 struct trie *t = (struct trie *) tb->tb_data;
2241 struct trie_stat stat;
2242
2243 if (!t)
2244 continue;
2238 2245
2239 tb = fib_get_table(net, RT_TABLE_MAIN); 2246 fib_table_print(seq, tb);
2240 if (tb) 2247
2241 fib_trie_show(seq, "Main", (struct trie *) tb->tb_data); 2248 trie_collect_stats(t, &stat);
2249 trie_show_stats(seq, &stat);
2250#ifdef CONFIG_IP_FIB_TRIE_STATS
2251 trie_show_usage(seq, &t->stats);
2252#endif
2253 }
2254 }
2242 2255
2243 return 0; 2256 return 0;
2244} 2257}
@@ -2274,67 +2287,79 @@ static const struct file_operations fib_triestat_fops = {
2274 .release = fib_triestat_seq_release, 2287 .release = fib_triestat_seq_release,
2275}; 2288};
2276 2289
2277static struct node *fib_trie_get_idx(struct fib_trie_iter *iter, 2290static struct node *fib_trie_get_idx(struct seq_file *seq, loff_t pos)
2278 loff_t pos)
2279{ 2291{
2292 struct fib_trie_iter *iter = seq->private;
2293 struct net *net = seq_file_net(seq);
2280 loff_t idx = 0; 2294 loff_t idx = 0;
2281 struct node *n; 2295 unsigned int h;
2282 2296
2283 for (n = fib_trie_get_first(iter, iter->trie_local); 2297 for (h = 0; h < FIB_TABLE_HASHSZ; h++) {
2284 n; ++idx, n = fib_trie_get_next(iter)) { 2298 struct hlist_head *head = &net->ipv4.fib_table_hash[h];
2285 if (pos == idx) 2299 struct hlist_node *node;
2286 return n; 2300 struct fib_table *tb;
2287 }
2288 2301
2289 for (n = fib_trie_get_first(iter, iter->trie_main); 2302 hlist_for_each_entry_rcu(tb, node, head, tb_hlist) {
2290 n; ++idx, n = fib_trie_get_next(iter)) { 2303 struct node *n;
2291 if (pos == idx) 2304
2292 return n; 2305 for (n = fib_trie_get_first(iter,
2306 (struct trie *) tb->tb_data);
2307 n; n = fib_trie_get_next(iter))
2308 if (pos == idx++) {
2309 iter->tb = tb;
2310 return n;
2311 }
2312 }
2293 } 2313 }
2314
2294 return NULL; 2315 return NULL;
2295} 2316}
2296 2317
2297static void *fib_trie_seq_start(struct seq_file *seq, loff_t *pos) 2318static void *fib_trie_seq_start(struct seq_file *seq, loff_t *pos)
2298 __acquires(RCU) 2319 __acquires(RCU)
2299{ 2320{
2300 struct fib_trie_iter *iter = seq->private;
2301 struct fib_table *tb;
2302
2303 if (!iter->trie_local) {
2304 tb = fib_get_table(iter->p.net, RT_TABLE_LOCAL);
2305 if (tb)
2306 iter->trie_local = (struct trie *) tb->tb_data;
2307 }
2308 if (!iter->trie_main) {
2309 tb = fib_get_table(iter->p.net, RT_TABLE_MAIN);
2310 if (tb)
2311 iter->trie_main = (struct trie *) tb->tb_data;
2312 }
2313 rcu_read_lock(); 2321 rcu_read_lock();
2314 if (*pos == 0) 2322 return fib_trie_get_idx(seq, *pos);
2315 return SEQ_START_TOKEN;
2316 return fib_trie_get_idx(iter, *pos - 1);
2317} 2323}
2318 2324
2319static void *fib_trie_seq_next(struct seq_file *seq, void *v, loff_t *pos) 2325static void *fib_trie_seq_next(struct seq_file *seq, void *v, loff_t *pos)
2320{ 2326{
2321 struct fib_trie_iter *iter = seq->private; 2327 struct fib_trie_iter *iter = seq->private;
2322 void *l = v; 2328 struct net *net = seq_file_net(seq);
2329 struct fib_table *tb = iter->tb;
2330 struct hlist_node *tb_node;
2331 unsigned int h;
2332 struct node *n;
2323 2333
2324 ++*pos; 2334 ++*pos;
2325 if (v == SEQ_START_TOKEN) 2335 /* next node in same table */
2326 return fib_trie_get_idx(iter, 0); 2336 n = fib_trie_get_next(iter);
2327 2337 if (n)
2328 v = fib_trie_get_next(iter); 2338 return n;
2329 BUG_ON(v == l);
2330 if (v)
2331 return v;
2332 2339
2333 /* continue scan in next trie */ 2340 /* walk rest of this hash chain */
2334 if (iter->trie == iter->trie_local) 2341 h = tb->tb_id & (FIB_TABLE_HASHSZ - 1);
2335 return fib_trie_get_first(iter, iter->trie_main); 2342 while ( (tb_node = rcu_dereference(tb->tb_hlist.next)) ) {
2343 tb = hlist_entry(tb_node, struct fib_table, tb_hlist);
2344 n = fib_trie_get_first(iter, (struct trie *) tb->tb_data);
2345 if (n)
2346 goto found;
2347 }
2336 2348
2349 /* new hash chain */
2350 while (++h < FIB_TABLE_HASHSZ) {
2351 struct hlist_head *head = &net->ipv4.fib_table_hash[h];
2352 hlist_for_each_entry_rcu(tb, tb_node, head, tb_hlist) {
2353 n = fib_trie_get_first(iter, (struct trie *) tb->tb_data);
2354 if (n)
2355 goto found;
2356 }
2357 }
2337 return NULL; 2358 return NULL;
2359
2360found:
2361 iter->tb = tb;
2362 return n;
2338} 2363}
2339 2364
2340static void fib_trie_seq_stop(struct seq_file *seq, void *v) 2365static void fib_trie_seq_stop(struct seq_file *seq, void *v)
@@ -2391,22 +2416,15 @@ static int fib_trie_seq_show(struct seq_file *seq, void *v)
2391 const struct fib_trie_iter *iter = seq->private; 2416 const struct fib_trie_iter *iter = seq->private;
2392 struct node *n = v; 2417 struct node *n = v;
2393 2418
2394 if (v == SEQ_START_TOKEN) 2419 if (!node_parent_rcu(n))
2395 return 0; 2420 fib_table_print(seq, iter->tb);
2396
2397 if (!node_parent_rcu(n)) {
2398 if (iter->trie == iter->trie_local)
2399 seq_puts(seq, "<local>:\n");
2400 else
2401 seq_puts(seq, "<main>:\n");
2402 }
2403 2421
2404 if (IS_TNODE(n)) { 2422 if (IS_TNODE(n)) {
2405 struct tnode *tn = (struct tnode *) n; 2423 struct tnode *tn = (struct tnode *) n;
2406 __be32 prf = htonl(mask_pfx(tn->key, tn->pos)); 2424 __be32 prf = htonl(mask_pfx(tn->key, tn->pos));
2407 2425
2408 seq_indent(seq, iter->depth-1); 2426 seq_indent(seq, iter->depth-1);
2409 seq_printf(seq, " +-- %d.%d.%d.%d/%d %d %d %d\n", 2427 seq_printf(seq, " +-- " NIPQUAD_FMT "/%d %d %d %d\n",
2410 NIPQUAD(prf), tn->pos, tn->bits, tn->full_children, 2428 NIPQUAD(prf), tn->pos, tn->bits, tn->full_children,
2411 tn->empty_children); 2429 tn->empty_children);
2412 2430
@@ -2417,7 +2435,7 @@ static int fib_trie_seq_show(struct seq_file *seq, void *v)
2417 __be32 val = htonl(l->key); 2435 __be32 val = htonl(l->key);
2418 2436
2419 seq_indent(seq, iter->depth); 2437 seq_indent(seq, iter->depth);
2420 seq_printf(seq, " |-- %d.%d.%d.%d\n", NIPQUAD(val)); 2438 seq_printf(seq, " |-- " NIPQUAD_FMT "\n", NIPQUAD(val));
2421 2439
2422 hlist_for_each_entry_rcu(li, node, &l->list, hlist) { 2440 hlist_for_each_entry_rcu(li, node, &l->list, hlist) {
2423 struct fib_alias *fa; 2441 struct fib_alias *fa;
@@ -2502,7 +2520,7 @@ static void *fib_route_seq_start(struct seq_file *seq, loff_t *pos)
2502 struct fib_table *tb; 2520 struct fib_table *tb;
2503 2521
2504 rcu_read_lock(); 2522 rcu_read_lock();
2505 tb = fib_get_table(iter->p.net, RT_TABLE_MAIN); 2523 tb = fib_get_table(seq_file_net(seq), RT_TABLE_MAIN);
2506 if (!tb) 2524 if (!tb)
2507 return NULL; 2525 return NULL;
2508 2526