diff options
Diffstat (limited to 'net/ipv4/fib_trie.c')
-rw-r--r-- | net/ipv4/fib_trie.c | 91 |
1 files changed, 40 insertions, 51 deletions
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index 4a8e370862bc..200eb538fbb3 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c | |||
@@ -16,7 +16,7 @@ | |||
16 | * | 16 | * |
17 | * An experimental study of compression methods for dynamic tries | 17 | * An experimental study of compression methods for dynamic tries |
18 | * Stefan Nilsson and Matti Tikkanen. Algorithmica, 33(1):19-33, 2002. | 18 | * Stefan Nilsson and Matti Tikkanen. Algorithmica, 33(1):19-33, 2002. |
19 | * http://www.nada.kth.se/~snilsson/public/papers/dyntrie2/ | 19 | * http://www.csc.kth.se/~snilsson/software/dyntrie2/ |
20 | * | 20 | * |
21 | * | 21 | * |
22 | * IP-address lookup using LC-tries. Stefan Nilsson and Gunnar Karlsson | 22 | * IP-address lookup using LC-tries. Stefan Nilsson and Gunnar Karlsson |
@@ -186,9 +186,7 @@ static inline struct tnode *node_parent_rcu(struct node *node) | |||
186 | { | 186 | { |
187 | struct tnode *ret = node_parent(node); | 187 | struct tnode *ret = node_parent(node); |
188 | 188 | ||
189 | return rcu_dereference_check(ret, | 189 | return rcu_dereference_rtnl(ret); |
190 | rcu_read_lock_held() || | ||
191 | lockdep_rtnl_is_held()); | ||
192 | } | 190 | } |
193 | 191 | ||
194 | /* Same as rcu_assign_pointer | 192 | /* Same as rcu_assign_pointer |
@@ -211,9 +209,7 @@ static inline struct node *tnode_get_child_rcu(struct tnode *tn, unsigned int i) | |||
211 | { | 209 | { |
212 | struct node *ret = tnode_get_child(tn, i); | 210 | struct node *ret = tnode_get_child(tn, i); |
213 | 211 | ||
214 | return rcu_dereference_check(ret, | 212 | return rcu_dereference_rtnl(ret); |
215 | rcu_read_lock_held() || | ||
216 | lockdep_rtnl_is_held()); | ||
217 | } | 213 | } |
218 | 214 | ||
219 | static inline int tnode_child_length(const struct tnode *tn) | 215 | static inline int tnode_child_length(const struct tnode *tn) |
@@ -459,8 +455,8 @@ static struct tnode *tnode_new(t_key key, int pos, int bits) | |||
459 | tn->empty_children = 1<<bits; | 455 | tn->empty_children = 1<<bits; |
460 | } | 456 | } |
461 | 457 | ||
462 | pr_debug("AT %p s=%u %lu\n", tn, (unsigned int) sizeof(struct tnode), | 458 | pr_debug("AT %p s=%zu %zu\n", tn, sizeof(struct tnode), |
463 | (unsigned long) (sizeof(struct node) << bits)); | 459 | sizeof(struct node) << bits); |
464 | return tn; | 460 | return tn; |
465 | } | 461 | } |
466 | 462 | ||
@@ -609,11 +605,10 @@ static struct node *resize(struct trie *t, struct tnode *tn) | |||
609 | 605 | ||
610 | /* Keep root node larger */ | 606 | /* Keep root node larger */ |
611 | 607 | ||
612 | if (!node_parent((struct node*) tn)) { | 608 | if (!node_parent((struct node *)tn)) { |
613 | inflate_threshold_use = inflate_threshold_root; | 609 | inflate_threshold_use = inflate_threshold_root; |
614 | halve_threshold_use = halve_threshold_root; | 610 | halve_threshold_use = halve_threshold_root; |
615 | } | 611 | } else { |
616 | else { | ||
617 | inflate_threshold_use = inflate_threshold; | 612 | inflate_threshold_use = inflate_threshold; |
618 | halve_threshold_use = halve_threshold; | 613 | halve_threshold_use = halve_threshold; |
619 | } | 614 | } |
@@ -639,7 +634,7 @@ static struct node *resize(struct trie *t, struct tnode *tn) | |||
639 | check_tnode(tn); | 634 | check_tnode(tn); |
640 | 635 | ||
641 | /* Return if at least one inflate is run */ | 636 | /* Return if at least one inflate is run */ |
642 | if( max_work != MAX_WORK) | 637 | if (max_work != MAX_WORK) |
643 | return (struct node *) tn; | 638 | return (struct node *) tn; |
644 | 639 | ||
645 | /* | 640 | /* |
@@ -966,9 +961,7 @@ fib_find_node(struct trie *t, u32 key) | |||
966 | struct node *n; | 961 | struct node *n; |
967 | 962 | ||
968 | pos = 0; | 963 | pos = 0; |
969 | n = rcu_dereference_check(t->trie, | 964 | n = rcu_dereference_rtnl(t->trie); |
970 | rcu_read_lock_held() || | ||
971 | lockdep_rtnl_is_held()); | ||
972 | 965 | ||
973 | while (n != NULL && NODE_TYPE(n) == T_TNODE) { | 966 | while (n != NULL && NODE_TYPE(n) == T_TNODE) { |
974 | tn = (struct tnode *) n; | 967 | tn = (struct tnode *) n; |
@@ -1349,7 +1342,7 @@ err: | |||
1349 | /* should be called with rcu_read_lock */ | 1342 | /* should be called with rcu_read_lock */ |
1350 | static int check_leaf(struct trie *t, struct leaf *l, | 1343 | static int check_leaf(struct trie *t, struct leaf *l, |
1351 | t_key key, const struct flowi *flp, | 1344 | t_key key, const struct flowi *flp, |
1352 | struct fib_result *res) | 1345 | struct fib_result *res, int fib_flags) |
1353 | { | 1346 | { |
1354 | struct leaf_info *li; | 1347 | struct leaf_info *li; |
1355 | struct hlist_head *hhead = &l->list; | 1348 | struct hlist_head *hhead = &l->list; |
@@ -1363,7 +1356,7 @@ static int check_leaf(struct trie *t, struct leaf *l, | |||
1363 | if (l->key != (key & ntohl(mask))) | 1356 | if (l->key != (key & ntohl(mask))) |
1364 | continue; | 1357 | continue; |
1365 | 1358 | ||
1366 | err = fib_semantic_match(&li->falh, flp, res, plen); | 1359 | err = fib_semantic_match(&li->falh, flp, res, plen, fib_flags); |
1367 | 1360 | ||
1368 | #ifdef CONFIG_IP_FIB_TRIE_STATS | 1361 | #ifdef CONFIG_IP_FIB_TRIE_STATS |
1369 | if (err <= 0) | 1362 | if (err <= 0) |
@@ -1379,7 +1372,7 @@ static int check_leaf(struct trie *t, struct leaf *l, | |||
1379 | } | 1372 | } |
1380 | 1373 | ||
1381 | int fib_table_lookup(struct fib_table *tb, const struct flowi *flp, | 1374 | int fib_table_lookup(struct fib_table *tb, const struct flowi *flp, |
1382 | struct fib_result *res) | 1375 | struct fib_result *res, int fib_flags) |
1383 | { | 1376 | { |
1384 | struct trie *t = (struct trie *) tb->tb_data; | 1377 | struct trie *t = (struct trie *) tb->tb_data; |
1385 | int ret; | 1378 | int ret; |
@@ -1391,8 +1384,7 @@ int fib_table_lookup(struct fib_table *tb, const struct flowi *flp, | |||
1391 | t_key cindex = 0; | 1384 | t_key cindex = 0; |
1392 | int current_prefix_length = KEYLENGTH; | 1385 | int current_prefix_length = KEYLENGTH; |
1393 | struct tnode *cn; | 1386 | struct tnode *cn; |
1394 | t_key node_prefix, key_prefix, pref_mismatch; | 1387 | t_key pref_mismatch; |
1395 | int mp; | ||
1396 | 1388 | ||
1397 | rcu_read_lock(); | 1389 | rcu_read_lock(); |
1398 | 1390 | ||
@@ -1406,7 +1398,7 @@ int fib_table_lookup(struct fib_table *tb, const struct flowi *flp, | |||
1406 | 1398 | ||
1407 | /* Just a leaf? */ | 1399 | /* Just a leaf? */ |
1408 | if (IS_LEAF(n)) { | 1400 | if (IS_LEAF(n)) { |
1409 | ret = check_leaf(t, (struct leaf *)n, key, flp, res); | 1401 | ret = check_leaf(t, (struct leaf *)n, key, flp, res, fib_flags); |
1410 | goto found; | 1402 | goto found; |
1411 | } | 1403 | } |
1412 | 1404 | ||
@@ -1431,7 +1423,7 @@ int fib_table_lookup(struct fib_table *tb, const struct flowi *flp, | |||
1431 | } | 1423 | } |
1432 | 1424 | ||
1433 | if (IS_LEAF(n)) { | 1425 | if (IS_LEAF(n)) { |
1434 | ret = check_leaf(t, (struct leaf *)n, key, flp, res); | 1426 | ret = check_leaf(t, (struct leaf *)n, key, flp, res, fib_flags); |
1435 | if (ret > 0) | 1427 | if (ret > 0) |
1436 | goto backtrace; | 1428 | goto backtrace; |
1437 | goto found; | 1429 | goto found; |
@@ -1507,10 +1499,7 @@ int fib_table_lookup(struct fib_table *tb, const struct flowi *flp, | |||
1507 | * matching prefix. | 1499 | * matching prefix. |
1508 | */ | 1500 | */ |
1509 | 1501 | ||
1510 | node_prefix = mask_pfx(cn->key, cn->pos); | 1502 | pref_mismatch = mask_pfx(cn->key ^ key, cn->pos); |
1511 | key_prefix = mask_pfx(key, cn->pos); | ||
1512 | pref_mismatch = key_prefix^node_prefix; | ||
1513 | mp = 0; | ||
1514 | 1503 | ||
1515 | /* | 1504 | /* |
1516 | * In short: If skipped bits in this node do not match | 1505 | * In short: If skipped bits in this node do not match |
@@ -1518,13 +1507,9 @@ int fib_table_lookup(struct fib_table *tb, const struct flowi *flp, | |||
1518 | * state.directly. | 1507 | * state.directly. |
1519 | */ | 1508 | */ |
1520 | if (pref_mismatch) { | 1509 | if (pref_mismatch) { |
1521 | while (!(pref_mismatch & (1<<(KEYLENGTH-1)))) { | 1510 | int mp = KEYLENGTH - fls(pref_mismatch); |
1522 | mp++; | ||
1523 | pref_mismatch = pref_mismatch << 1; | ||
1524 | } | ||
1525 | key_prefix = tkey_extract_bits(cn->key, mp, cn->pos-mp); | ||
1526 | 1511 | ||
1527 | if (key_prefix != 0) | 1512 | if (tkey_extract_bits(cn->key, mp, cn->pos - mp) != 0) |
1528 | goto backtrace; | 1513 | goto backtrace; |
1529 | 1514 | ||
1530 | if (current_prefix_length >= cn->pos) | 1515 | if (current_prefix_length >= cn->pos) |
@@ -1748,16 +1733,14 @@ static struct leaf *leaf_walk_rcu(struct tnode *p, struct node *c) | |||
1748 | 1733 | ||
1749 | /* Node empty, walk back up to parent */ | 1734 | /* Node empty, walk back up to parent */ |
1750 | c = (struct node *) p; | 1735 | c = (struct node *) p; |
1751 | } while ( (p = node_parent_rcu(c)) != NULL); | 1736 | } while ((p = node_parent_rcu(c)) != NULL); |
1752 | 1737 | ||
1753 | return NULL; /* Root of trie */ | 1738 | return NULL; /* Root of trie */ |
1754 | } | 1739 | } |
1755 | 1740 | ||
1756 | static struct leaf *trie_firstleaf(struct trie *t) | 1741 | static struct leaf *trie_firstleaf(struct trie *t) |
1757 | { | 1742 | { |
1758 | struct tnode *n = (struct tnode *) rcu_dereference_check(t->trie, | 1743 | struct tnode *n = (struct tnode *)rcu_dereference_rtnl(t->trie); |
1759 | rcu_read_lock_held() || | ||
1760 | lockdep_rtnl_is_held()); | ||
1761 | 1744 | ||
1762 | if (!n) | 1745 | if (!n) |
1763 | return NULL; | 1746 | return NULL; |
@@ -1814,6 +1797,11 @@ int fib_table_flush(struct fib_table *tb) | |||
1814 | return found; | 1797 | return found; |
1815 | } | 1798 | } |
1816 | 1799 | ||
1800 | void fib_free_table(struct fib_table *tb) | ||
1801 | { | ||
1802 | kfree(tb); | ||
1803 | } | ||
1804 | |||
1817 | void fib_table_select_default(struct fib_table *tb, | 1805 | void fib_table_select_default(struct fib_table *tb, |
1818 | const struct flowi *flp, | 1806 | const struct flowi *flp, |
1819 | struct fib_result *res) | 1807 | struct fib_result *res) |
@@ -1855,7 +1843,8 @@ void fib_table_select_default(struct fib_table *tb, | |||
1855 | if (!next_fi->fib_nh[0].nh_gw || | 1843 | if (!next_fi->fib_nh[0].nh_gw || |
1856 | next_fi->fib_nh[0].nh_scope != RT_SCOPE_LINK) | 1844 | next_fi->fib_nh[0].nh_scope != RT_SCOPE_LINK) |
1857 | continue; | 1845 | continue; |
1858 | fa->fa_state |= FA_S_ACCESSED; | 1846 | |
1847 | fib_alias_accessed(fa); | ||
1859 | 1848 | ||
1860 | if (fi == NULL) { | 1849 | if (fi == NULL) { |
1861 | if (next_fi != res->fi) | 1850 | if (next_fi != res->fi) |
@@ -2043,14 +2032,14 @@ struct fib_trie_iter { | |||
2043 | struct seq_net_private p; | 2032 | struct seq_net_private p; |
2044 | struct fib_table *tb; | 2033 | struct fib_table *tb; |
2045 | struct tnode *tnode; | 2034 | struct tnode *tnode; |
2046 | unsigned index; | 2035 | unsigned int index; |
2047 | unsigned depth; | 2036 | unsigned int depth; |
2048 | }; | 2037 | }; |
2049 | 2038 | ||
2050 | static struct node *fib_trie_get_next(struct fib_trie_iter *iter) | 2039 | static struct node *fib_trie_get_next(struct fib_trie_iter *iter) |
2051 | { | 2040 | { |
2052 | struct tnode *tn = iter->tnode; | 2041 | struct tnode *tn = iter->tnode; |
2053 | unsigned cindex = iter->index; | 2042 | unsigned int cindex = iter->index; |
2054 | struct tnode *p; | 2043 | struct tnode *p; |
2055 | 2044 | ||
2056 | /* A single entry routing table */ | 2045 | /* A single entry routing table */ |
@@ -2159,7 +2148,7 @@ static void trie_collect_stats(struct trie *t, struct trie_stat *s) | |||
2159 | */ | 2148 | */ |
2160 | static void trie_show_stats(struct seq_file *seq, struct trie_stat *stat) | 2149 | static void trie_show_stats(struct seq_file *seq, struct trie_stat *stat) |
2161 | { | 2150 | { |
2162 | unsigned i, max, pointers, bytes, avdepth; | 2151 | unsigned int i, max, pointers, bytes, avdepth; |
2163 | 2152 | ||
2164 | if (stat->leaves) | 2153 | if (stat->leaves) |
2165 | avdepth = stat->totdepth*100 / stat->leaves; | 2154 | avdepth = stat->totdepth*100 / stat->leaves; |
@@ -2356,7 +2345,8 @@ static void fib_trie_seq_stop(struct seq_file *seq, void *v) | |||
2356 | 2345 | ||
2357 | static void seq_indent(struct seq_file *seq, int n) | 2346 | static void seq_indent(struct seq_file *seq, int n) |
2358 | { | 2347 | { |
2359 | while (n-- > 0) seq_puts(seq, " "); | 2348 | while (n-- > 0) |
2349 | seq_puts(seq, " "); | ||
2360 | } | 2350 | } |
2361 | 2351 | ||
2362 | static inline const char *rtn_scope(char *buf, size_t len, enum rt_scope_t s) | 2352 | static inline const char *rtn_scope(char *buf, size_t len, enum rt_scope_t s) |
@@ -2388,7 +2378,7 @@ static const char *const rtn_type_names[__RTN_MAX] = { | |||
2388 | [RTN_XRESOLVE] = "XRESOLVE", | 2378 | [RTN_XRESOLVE] = "XRESOLVE", |
2389 | }; | 2379 | }; |
2390 | 2380 | ||
2391 | static inline const char *rtn_type(char *buf, size_t len, unsigned t) | 2381 | static inline const char *rtn_type(char *buf, size_t len, unsigned int t) |
2392 | { | 2382 | { |
2393 | if (t < __RTN_MAX && rtn_type_names[t]) | 2383 | if (t < __RTN_MAX && rtn_type_names[t]) |
2394 | return rtn_type_names[t]; | 2384 | return rtn_type_names[t]; |
@@ -2544,13 +2534,12 @@ static void fib_route_seq_stop(struct seq_file *seq, void *v) | |||
2544 | rcu_read_unlock(); | 2534 | rcu_read_unlock(); |
2545 | } | 2535 | } |
2546 | 2536 | ||
2547 | static unsigned fib_flag_trans(int type, __be32 mask, const struct fib_info *fi) | 2537 | static unsigned int fib_flag_trans(int type, __be32 mask, const struct fib_info *fi) |
2548 | { | 2538 | { |
2549 | static unsigned type2flags[RTN_MAX + 1] = { | 2539 | unsigned int flags = 0; |
2550 | [7] = RTF_REJECT, [8] = RTF_REJECT, | ||
2551 | }; | ||
2552 | unsigned flags = type2flags[type]; | ||
2553 | 2540 | ||
2541 | if (type == RTN_UNREACHABLE || type == RTN_PROHIBIT) | ||
2542 | flags = RTF_REJECT; | ||
2554 | if (fi && fi->fib_nh->nh_gw) | 2543 | if (fi && fi->fib_nh->nh_gw) |
2555 | flags |= RTF_GATEWAY; | 2544 | flags |= RTF_GATEWAY; |
2556 | if (mask == htonl(0xFFFFFFFF)) | 2545 | if (mask == htonl(0xFFFFFFFF)) |
@@ -2562,7 +2551,7 @@ static unsigned fib_flag_trans(int type, __be32 mask, const struct fib_info *fi) | |||
2562 | /* | 2551 | /* |
2563 | * This outputs /proc/net/route. | 2552 | * This outputs /proc/net/route. |
2564 | * The format of the file is not supposed to be changed | 2553 | * The format of the file is not supposed to be changed |
2565 | * and needs to be same as fib_hash output to avoid breaking | 2554 | * and needs to be same as fib_hash output to avoid breaking |
2566 | * legacy utilities | 2555 | * legacy utilities |
2567 | */ | 2556 | */ |
2568 | static int fib_route_seq_show(struct seq_file *seq, void *v) | 2557 | static int fib_route_seq_show(struct seq_file *seq, void *v) |
@@ -2587,7 +2576,7 @@ static int fib_route_seq_show(struct seq_file *seq, void *v) | |||
2587 | 2576 | ||
2588 | list_for_each_entry_rcu(fa, &li->falh, fa_list) { | 2577 | list_for_each_entry_rcu(fa, &li->falh, fa_list) { |
2589 | const struct fib_info *fi = fa->fa_info; | 2578 | const struct fib_info *fi = fa->fa_info; |
2590 | unsigned flags = fib_flag_trans(fa->fa_type, mask, fi); | 2579 | unsigned int flags = fib_flag_trans(fa->fa_type, mask, fi); |
2591 | int len; | 2580 | int len; |
2592 | 2581 | ||
2593 | if (fa->fa_type == RTN_BROADCAST | 2582 | if (fa->fa_type == RTN_BROADCAST |