aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/fib_trie.c
diff options
context:
space:
mode:
authorAlexander Duyck <alexander.h.duyck@redhat.com>2015-03-04 17:58:19 -0500
committerDavid S. Miller <davem@davemloft.net>2015-03-04 23:35:17 -0500
commit7289e6ddb633aaee6ccea2bd2e410654c47b29a6 (patch)
treeabef72d0cdcb8e0701e6b97c9b3481ca01cd4566 /net/ipv4/fib_trie.c
parent3a65f63ff6780d35aec355b440eb39bbfbe1b8f5 (diff)
fib_trie: Only resize tnodes once instead of on each leaf removal in fib_table_flush
This change makes it so that we only call resize on the tnodes, instead of from each of the leaves. By doing this we can significantly reduce the amount of time spent resizing as we can update all of the leaves in the tnode first before we make any determinations about resizing. As a result we can simply free the tnode in the case that all of the leaves from a given tnode are flushed instead of resizing with each leaf removed. Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/fib_trie.c')
-rw-r--r--net/ipv4/fib_trie.c141
1 files changed, 78 insertions, 63 deletions
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index f48534577f8d..d8b68b4de532 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -1400,25 +1400,6 @@ found:
1400EXPORT_SYMBOL_GPL(fib_table_lookup); 1400EXPORT_SYMBOL_GPL(fib_table_lookup);
1401 1401
1402/* 1402/*
1403 * Remove the leaf and return parent.
1404 */
1405static void trie_leaf_remove(struct trie *t, struct tnode *l)
1406{
1407 struct tnode *tp = node_parent(l);
1408
1409 pr_debug("entering trie_leaf_remove(%p)\n", l);
1410
1411 if (tp) {
1412 put_child(tp, get_index(l->key, tp), NULL);
1413 trie_rebalance(t, tp);
1414 } else {
1415 RCU_INIT_POINTER(t->trie, NULL);
1416 }
1417
1418 node_free(l);
1419}
1420
1421/*
1422 * Caller must hold RTNL. 1403 * Caller must hold RTNL.
1423 */ 1404 */
1424int fib_table_delete(struct fib_table *tb, struct fib_config *cfg) 1405int fib_table_delete(struct fib_table *tb, struct fib_config *cfg)
@@ -1483,8 +1464,18 @@ int fib_table_delete(struct fib_table *tb, struct fib_config *cfg)
1483 if (!plen) 1464 if (!plen)
1484 tb->tb_num_default--; 1465 tb->tb_num_default--;
1485 1466
1486 if (hlist_empty(&l->leaf)) 1467 if (hlist_empty(&l->leaf)) {
1487 trie_leaf_remove(t, l); 1468 struct tnode *tp = node_parent(l);
1469
1470 if (tp) {
1471 put_child(tp, get_index(l->key, tp), NULL);
1472 trie_rebalance(t, tp);
1473 } else {
1474 RCU_INIT_POINTER(t->trie, NULL);
1475 }
1476
1477 node_free(l);
1478 }
1488 1479
1489 if (fa->fa_state & FA_S_ACCESSED) 1480 if (fa->fa_state & FA_S_ACCESSED)
1490 rt_cache_flush(cfg->fc_nlinfo.nl_net); 1481 rt_cache_flush(cfg->fc_nlinfo.nl_net);
@@ -1494,33 +1485,6 @@ int fib_table_delete(struct fib_table *tb, struct fib_config *cfg)
1494 return 0; 1485 return 0;
1495} 1486}
1496 1487
1497static int trie_flush_leaf(struct tnode *l)
1498{
1499 struct hlist_node *tmp;
1500 unsigned char slen = 0;
1501 struct fib_alias *fa;
1502 int found = 0;
1503
1504 hlist_for_each_entry_safe(fa, tmp, &l->leaf, fa_list) {
1505 struct fib_info *fi = fa->fa_info;
1506
1507 if (fi && (fi->fib_flags & RTNH_F_DEAD)) {
1508 hlist_del_rcu(&fa->fa_list);
1509 fib_release_info(fa->fa_info);
1510 alias_free_mem_rcu(fa);
1511 found++;
1512
1513 continue;
1514 }
1515
1516 slen = fa->fa_slen;
1517 }
1518
1519 l->slen = slen;
1520
1521 return found;
1522}
1523
1524/* Scan for the next right leaf starting at node p->child[idx] 1488/* Scan for the next right leaf starting at node p->child[idx]
1525 * Since we have back pointer, no recursion necessary. 1489 * Since we have back pointer, no recursion necessary.
1526 */ 1490 */
@@ -1588,30 +1552,81 @@ static struct tnode *trie_leafindex(struct trie *t, int index)
1588 */ 1552 */
1589int fib_table_flush(struct fib_table *tb) 1553int fib_table_flush(struct fib_table *tb)
1590{ 1554{
1591 struct trie *t = (struct trie *) tb->tb_data; 1555 struct trie *t = (struct trie *)tb->tb_data;
1592 struct tnode *l, *ll = NULL; 1556 struct hlist_node *tmp;
1557 struct fib_alias *fa;
1558 struct tnode *n, *pn;
1559 unsigned long cindex;
1560 unsigned char slen;
1593 int found = 0; 1561 int found = 0;
1594 1562
1595 for (l = trie_firstleaf(t); l; l = trie_nextleaf(l)) { 1563 n = rcu_dereference(t->trie);
1596 found += trie_flush_leaf(l); 1564 if (!n)
1565 goto flush_complete;
1566
1567 pn = NULL;
1568 cindex = 0;
1569
1570 while (IS_TNODE(n)) {
1571 /* record pn and cindex for leaf walking */
1572 pn = n;
1573 cindex = 1ul << n->bits;
1574backtrace:
1575 /* walk trie in reverse order */
1576 do {
1577 while (!(cindex--)) {
1578 t_key pkey = pn->key;
1579
1580 n = pn;
1581 pn = node_parent(n);
1582
1583 /* resize completed node */
1584 resize(t, n);
1585
1586 /* if we got the root we are done */
1587 if (!pn)
1588 goto flush_complete;
1597 1589
1598 if (ll) { 1590 cindex = get_index(pkey, pn);
1599 if (hlist_empty(&ll->leaf)) 1591 }
1600 trie_leaf_remove(t, ll); 1592
1601 else 1593 /* grab the next available node */
1602 leaf_pull_suffix(ll); 1594 n = tnode_get_child(pn, cindex);
1595 } while (!n);
1596 }
1597
1598 /* track slen in case any prefixes survive */
1599 slen = 0;
1600
1601 hlist_for_each_entry_safe(fa, tmp, &n->leaf, fa_list) {
1602 struct fib_info *fi = fa->fa_info;
1603
1604 if (fi && (fi->fib_flags & RTNH_F_DEAD)) {
1605 hlist_del_rcu(&fa->fa_list);
1606 fib_release_info(fa->fa_info);
1607 alias_free_mem_rcu(fa);
1608 found++;
1609
1610 continue;
1603 } 1611 }
1604 1612
1605 ll = l; 1613 slen = fa->fa_slen;
1606 } 1614 }
1607 1615
1608 if (ll) { 1616 /* update leaf slen */
1609 if (hlist_empty(&ll->leaf)) 1617 n->slen = slen;
1610 trie_leaf_remove(t, ll); 1618
1611 else 1619 if (hlist_empty(&n->leaf)) {
1612 leaf_pull_suffix(ll); 1620 put_child_root(pn, t, n->key, NULL);
1621 node_free(n);
1622 } else {
1623 leaf_pull_suffix(n);
1613 } 1624 }
1614 1625
1626 /* if trie is leaf only loop is completed */
1627 if (pn)
1628 goto backtrace;
1629flush_complete:
1615 pr_debug("trie_flush found=%d\n", found); 1630 pr_debug("trie_flush found=%d\n", found);
1616 return found; 1631 return found;
1617} 1632}