Skip to content

Commit 7289e6d

Browse files
Alexander Duyckdavem330
authored andcommitted
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 <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 3a65f63 commit 7289e6d

File tree

1 file changed

+78
-63
lines changed

1 file changed

+78
-63
lines changed

net/ipv4/fib_trie.c

Lines changed: 78 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1399,25 +1399,6 @@ int fib_table_lookup(struct fib_table *tb, const struct flowi4 *flp,
13991399
}
14001400
EXPORT_SYMBOL_GPL(fib_table_lookup);
14011401

1402-
/*
1403-
* Remove the leaf and return parent.
1404-
*/
1405-
static 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-
14211402
/*
14221403
* Caller must hold RTNL.
14231404
*/
@@ -1483,8 +1464,18 @@ int fib_table_delete(struct fib_table *tb, struct fib_config *cfg)
14831464
if (!plen)
14841465
tb->tb_num_default--;
14851466

1486-
if (hlist_empty(&l->leaf))
1487-
trie_leaf_remove(t, l);
1467+
if (hlist_empty(&l->leaf)) {
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+
}
14881479

14891480
if (fa->fa_state & FA_S_ACCESSED)
14901481
rt_cache_flush(cfg->fc_nlinfo.nl_net);
@@ -1494,33 +1485,6 @@ int fib_table_delete(struct fib_table *tb, struct fib_config *cfg)
14941485
return 0;
14951486
}
14961487

1497-
static 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-
15241488
/* Scan for the next right leaf starting at node p->child[idx]
15251489
* Since we have back pointer, no recursion necessary.
15261490
*/
@@ -1588,30 +1552,81 @@ static struct tnode *trie_leafindex(struct trie *t, int index)
15881552
*/
15891553
int fib_table_flush(struct fib_table *tb)
15901554
{
1591-
struct trie *t = (struct trie *) tb->tb_data;
1592-
struct tnode *l, *ll = NULL;
1555+
struct trie *t = (struct trie *)tb->tb_data;
1556+
struct hlist_node *tmp;
1557+
struct fib_alias *fa;
1558+
struct tnode *n, *pn;
1559+
unsigned long cindex;
1560+
unsigned char slen;
15931561
int found = 0;
15941562

1595-
for (l = trie_firstleaf(t); l; l = trie_nextleaf(l)) {
1596-
found += trie_flush_leaf(l);
1563+
n = rcu_dereference(t->trie);
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;
1574+
backtrace:
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;
15971589

1598-
if (ll) {
1599-
if (hlist_empty(&ll->leaf))
1600-
trie_leaf_remove(t, ll);
1601-
else
1602-
leaf_pull_suffix(ll);
1590+
cindex = get_index(pkey, pn);
1591+
}
1592+
1593+
/* grab the next available node */
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;
16031611
}
16041612

1605-
ll = l;
1613+
slen = fa->fa_slen;
16061614
}
16071615

1608-
if (ll) {
1609-
if (hlist_empty(&ll->leaf))
1610-
trie_leaf_remove(t, ll);
1611-
else
1612-
leaf_pull_suffix(ll);
1616+
/* update leaf slen */
1617+
n->slen = slen;
1618+
1619+
if (hlist_empty(&n->leaf)) {
1620+
put_child_root(pn, t, n->key, NULL);
1621+
node_free(n);
1622+
} else {
1623+
leaf_pull_suffix(n);
16131624
}
16141625

1626+
/* if trie is leaf only loop is completed */
1627+
if (pn)
1628+
goto backtrace;
1629+
flush_complete:
16151630
pr_debug("trie_flush found=%d\n", found);
16161631
return found;
16171632
}

0 commit comments

Comments
 (0)