Skip to content

Commit 8be33e9

Browse files
Alexander Duyckdavem330
authored andcommitted
fib_trie: Fib walk rcu should take a tnode and key instead of a trie and a leaf
This change makes it so that leaf_walk_rcu takes a tnode and a key instead of the trie and a leaf. The main idea behind this is to avoid using the leaf parent pointer as that can have additional overhead in the future as I am trying to reduce the size of a leaf down to 16 bytes on 64b systems and 12b on 32b systems. Signed-off-by: Alexander Duyck <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 7289e6d commit 8be33e9

File tree

1 file changed

+120
-96
lines changed

1 file changed

+120
-96
lines changed

net/ipv4/fib_trie.c

Lines changed: 120 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -1485,71 +1485,71 @@ int fib_table_delete(struct fib_table *tb, struct fib_config *cfg)
14851485
return 0;
14861486
}
14871487

1488-
/* Scan for the next right leaf starting at node p->child[idx]
1489-
* Since we have back pointer, no recursion necessary.
1490-
*/
1491-
static struct tnode *leaf_walk_rcu(struct tnode *p, struct tnode *c)
1488+
/* Scan for the next leaf starting at the provided key value */
1489+
static struct tnode *leaf_walk_rcu(struct tnode **tn, t_key key)
14921490
{
1493-
do {
1494-
unsigned long idx = c ? idx = get_index(c->key, p) + 1 : 0;
1495-
1496-
while (idx < tnode_child_length(p)) {
1497-
c = tnode_get_child_rcu(p, idx++);
1498-
if (!c)
1499-
continue;
1500-
1501-
if (IS_LEAF(c))
1502-
return c;
1503-
1504-
/* Rescan start scanning in new node */
1505-
p = c;
1506-
idx = 0;
1507-
}
1491+
struct tnode *pn, *n = *tn;
1492+
unsigned long cindex;
15081493

1509-
/* Node empty, walk back up to parent */
1510-
c = p;
1511-
} while ((p = node_parent_rcu(c)) != NULL);
1494+
/* record parent node for backtracing */
1495+
pn = n;
1496+
cindex = n ? get_index(key, n) : 0;
15121497

1513-
return NULL; /* Root of trie */
1514-
}
1498+
/* this loop is meant to try and find the key in the trie */
1499+
while (n) {
1500+
unsigned long idx = get_index(key, n);
15151501

1516-
static struct tnode *trie_firstleaf(struct trie *t)
1517-
{
1518-
struct tnode *n = rcu_dereference_rtnl(t->trie);
1502+
/* guarantee forward progress on the keys */
1503+
if (IS_LEAF(n) && (n->key >= key))
1504+
goto found;
1505+
if (idx >= (1ul << n->bits))
1506+
break;
15191507

1520-
if (!n)
1521-
return NULL;
1508+
/* record parent and next child index */
1509+
pn = n;
1510+
cindex = idx;
15221511

1523-
if (IS_LEAF(n)) /* trie is just a leaf */
1524-
return n;
1512+
/* descend into the next child */
1513+
n = tnode_get_child_rcu(pn, cindex++);
1514+
}
15251515

1526-
return leaf_walk_rcu(n, NULL);
1527-
}
1516+
/* this loop will search for the next leaf with a greater key */
1517+
while (pn) {
1518+
/* if we exhausted the parent node we will need to climb */
1519+
if (cindex >= (1ul << pn->bits)) {
1520+
t_key pkey = pn->key;
15281521

1529-
static struct tnode *trie_nextleaf(struct tnode *l)
1530-
{
1531-
struct tnode *p = node_parent_rcu(l);
1522+
pn = node_parent_rcu(pn);
1523+
if (!pn)
1524+
break;
15321525

1533-
if (!p)
1534-
return NULL; /* trie with just one leaf */
1526+
cindex = get_index(pkey, pn) + 1;
1527+
continue;
1528+
}
15351529

1536-
return leaf_walk_rcu(p, l);
1537-
}
1530+
/* grab the next available node */
1531+
n = tnode_get_child_rcu(pn, cindex++);
1532+
if (!n)
1533+
continue;
15381534

1539-
static struct tnode *trie_leafindex(struct trie *t, int index)
1540-
{
1541-
struct tnode *l = trie_firstleaf(t);
1535+
/* no need to compare keys since we bumped the index */
1536+
if (IS_LEAF(n))
1537+
goto found;
15421538

1543-
while (l && index-- > 0)
1544-
l = trie_nextleaf(l);
1539+
/* Rescan start scanning in new node */
1540+
pn = n;
1541+
cindex = 0;
1542+
}
15451543

1546-
return l;
1544+
*tn = pn;
1545+
return NULL; /* Root of trie */
1546+
found:
1547+
/* if we are at the limit for keys just return NULL for the tnode */
1548+
*tn = (n->key == KEY_MAX) ? NULL : pn;
1549+
return n;
15471550
}
15481551

1549-
1550-
/*
1551-
* Caller must hold RTNL.
1552-
*/
1552+
/* Caller must hold RTNL. */
15531553
int fib_table_flush(struct fib_table *tb)
15541554
{
15551555
struct trie *t = (struct trie *)tb->tb_data;
@@ -1680,42 +1680,42 @@ static int fn_trie_dump_leaf(struct tnode *l, struct fib_table *tb,
16801680
int fib_table_dump(struct fib_table *tb, struct sk_buff *skb,
16811681
struct netlink_callback *cb)
16821682
{
1683-
struct tnode *l;
1684-
struct trie *t = (struct trie *) tb->tb_data;
1685-
t_key key = cb->args[2];
1686-
int count = cb->args[3];
1687-
1688-
rcu_read_lock();
1683+
struct trie *t = (struct trie *)tb->tb_data;
1684+
struct tnode *l, *tp;
16891685
/* Dump starting at last key.
16901686
* Note: 0.0.0.0/0 (ie default) is first key.
16911687
*/
1692-
if (count == 0)
1693-
l = trie_firstleaf(t);
1694-
else {
1695-
/* Normally, continue from last key, but if that is missing
1696-
* fallback to using slow rescan
1697-
*/
1698-
l = fib_find_node(t, key);
1699-
if (!l)
1700-
l = trie_leafindex(t, count);
1701-
}
1688+
int count = cb->args[2];
1689+
t_key key = cb->args[3];
17021690

1703-
while (l) {
1704-
cb->args[2] = l->key;
1691+
rcu_read_lock();
1692+
1693+
tp = rcu_dereference_rtnl(t->trie);
1694+
1695+
while ((l = leaf_walk_rcu(&tp, key)) != NULL) {
17051696
if (fn_trie_dump_leaf(l, tb, skb, cb) < 0) {
1706-
cb->args[3] = count;
1697+
cb->args[3] = key;
1698+
cb->args[2] = count;
17071699
rcu_read_unlock();
17081700
return -1;
17091701
}
17101702

17111703
++count;
1712-
l = trie_nextleaf(l);
1704+
key = l->key + 1;
1705+
17131706
memset(&cb->args[4], 0,
17141707
sizeof(cb->args) - 4*sizeof(cb->args[0]));
1708+
1709+
/* stop loop if key wrapped back to 0 */
1710+
if (key < l->key)
1711+
break;
17151712
}
1716-
cb->args[3] = count;
1713+
17171714
rcu_read_unlock();
17181715

1716+
cb->args[3] = key;
1717+
cb->args[2] = count;
1718+
17191719
return skb->len;
17201720
}
17211721

@@ -2186,31 +2186,46 @@ static const struct file_operations fib_trie_fops = {
21862186

21872187
struct fib_route_iter {
21882188
struct seq_net_private p;
2189-
struct trie *main_trie;
2189+
struct fib_table *main_tb;
2190+
struct tnode *tnode;
21902191
loff_t pos;
21912192
t_key key;
21922193
};
21932194

21942195
static struct tnode *fib_route_get_idx(struct fib_route_iter *iter, loff_t pos)
21952196
{
2196-
struct tnode *l = NULL;
2197-
struct trie *t = iter->main_trie;
2197+
struct fib_table *tb = iter->main_tb;
2198+
struct tnode *l, **tp = &iter->tnode;
2199+
struct trie *t;
2200+
t_key key;
21982201

2199-
/* use cache location of last found key */
2200-
if (iter->pos > 0 && pos >= iter->pos && (l = fib_find_node(t, iter->key)))
2202+
/* use cache location of next-to-find key */
2203+
if (iter->pos > 0 && pos >= iter->pos) {
22012204
pos -= iter->pos;
2202-
else {
2205+
key = iter->key;
2206+
} else {
2207+
t = (struct trie *)tb->tb_data;
2208+
iter->tnode = rcu_dereference_rtnl(t->trie);
22032209
iter->pos = 0;
2204-
l = trie_firstleaf(t);
2210+
key = 0;
22052211
}
22062212

2207-
while (l && pos-- > 0) {
2213+
while ((l = leaf_walk_rcu(tp, key)) != NULL) {
2214+
key = l->key + 1;
22082215
iter->pos++;
2209-
l = trie_nextleaf(l);
2216+
2217+
if (pos-- <= 0)
2218+
break;
2219+
2220+
l = NULL;
2221+
2222+
/* handle unlikely case of a key wrap */
2223+
if (!key)
2224+
break;
22102225
}
22112226

22122227
if (l)
2213-
iter->key = pos; /* remember it */
2228+
iter->key = key; /* remember it */
22142229
else
22152230
iter->pos = 0; /* forget it */
22162231

@@ -2222,37 +2237,46 @@ static void *fib_route_seq_start(struct seq_file *seq, loff_t *pos)
22222237
{
22232238
struct fib_route_iter *iter = seq->private;
22242239
struct fib_table *tb;
2240+
struct trie *t;
22252241

22262242
rcu_read_lock();
2243+
22272244
tb = fib_get_table(seq_file_net(seq), RT_TABLE_MAIN);
22282245
if (!tb)
22292246
return NULL;
22302247

2231-
iter->main_trie = (struct trie *) tb->tb_data;
2232-
if (*pos == 0)
2233-
return SEQ_START_TOKEN;
2234-
else
2235-
return fib_route_get_idx(iter, *pos - 1);
2248+
iter->main_tb = tb;
2249+
2250+
if (*pos != 0)
2251+
return fib_route_get_idx(iter, *pos);
2252+
2253+
t = (struct trie *)tb->tb_data;
2254+
iter->tnode = rcu_dereference_rtnl(t->trie);
2255+
iter->pos = 0;
2256+
iter->key = 0;
2257+
2258+
return SEQ_START_TOKEN;
22362259
}
22372260

22382261
static void *fib_route_seq_next(struct seq_file *seq, void *v, loff_t *pos)
22392262
{
22402263
struct fib_route_iter *iter = seq->private;
2241-
struct tnode *l = v;
2264+
struct tnode *l = NULL;
2265+
t_key key = iter->key;
22422266

22432267
++*pos;
2244-
if (v == SEQ_START_TOKEN) {
2245-
iter->pos = 0;
2246-
l = trie_firstleaf(iter->main_trie);
2247-
} else {
2268+
2269+
/* only allow key of 0 for start of sequence */
2270+
if ((v == SEQ_START_TOKEN) || key)
2271+
l = leaf_walk_rcu(&iter->tnode, key);
2272+
2273+
if (l) {
2274+
iter->key = l->key + 1;
22482275
iter->pos++;
2249-
l = trie_nextleaf(l);
2276+
} else {
2277+
iter->pos = 0;
22502278
}
22512279

2252-
if (l)
2253-
iter->key = l->key;
2254-
else
2255-
iter->pos = 0;
22562280
return l;
22572281
}
22582282

0 commit comments

Comments
 (0)