@@ -1485,71 +1485,71 @@ int fib_table_delete(struct fib_table *tb, struct fib_config *cfg)
1485
1485
return 0 ;
1486
1486
}
1487
1487
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 )
1492
1490
{
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 ;
1508
1493
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 ;
1512
1497
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 );
1515
1501
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 ;
1519
1507
1520
- if (!n )
1521
- return NULL ;
1508
+ /* record parent and next child index */
1509
+ pn = n ;
1510
+ cindex = idx ;
1522
1511
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
+ }
1525
1515
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 ;
1528
1521
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 ;
1532
1525
1533
- if (!p )
1534
- return NULL ; /* trie with just one leaf */
1526
+ cindex = get_index (pkey , pn ) + 1 ;
1527
+ continue ;
1528
+ }
1535
1529
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 ;
1538
1534
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 ;
1542
1538
1543
- while (l && index -- > 0 )
1544
- l = trie_nextleaf (l );
1539
+ /* Rescan start scanning in new node */
1540
+ pn = n ;
1541
+ cindex = 0 ;
1542
+ }
1545
1543
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 ;
1547
1550
}
1548
1551
1549
-
1550
- /*
1551
- * Caller must hold RTNL.
1552
- */
1552
+ /* Caller must hold RTNL. */
1553
1553
int fib_table_flush (struct fib_table * tb )
1554
1554
{
1555
1555
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,
1680
1680
int fib_table_dump (struct fib_table * tb , struct sk_buff * skb ,
1681
1681
struct netlink_callback * cb )
1682
1682
{
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 ;
1689
1685
/* Dump starting at last key.
1690
1686
* Note: 0.0.0.0/0 (ie default) is first key.
1691
1687
*/
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 ];
1702
1690
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 ) {
1705
1696
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 ;
1707
1699
rcu_read_unlock ();
1708
1700
return -1 ;
1709
1701
}
1710
1702
1711
1703
++ count ;
1712
- l = trie_nextleaf (l );
1704
+ key = l -> key + 1 ;
1705
+
1713
1706
memset (& cb -> args [4 ], 0 ,
1714
1707
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 ;
1715
1712
}
1716
- cb -> args [ 3 ] = count ;
1713
+
1717
1714
rcu_read_unlock ();
1718
1715
1716
+ cb -> args [3 ] = key ;
1717
+ cb -> args [2 ] = count ;
1718
+
1719
1719
return skb -> len ;
1720
1720
}
1721
1721
@@ -2186,31 +2186,46 @@ static const struct file_operations fib_trie_fops = {
2186
2186
2187
2187
struct fib_route_iter {
2188
2188
struct seq_net_private p ;
2189
- struct trie * main_trie ;
2189
+ struct fib_table * main_tb ;
2190
+ struct tnode * tnode ;
2190
2191
loff_t pos ;
2191
2192
t_key key ;
2192
2193
};
2193
2194
2194
2195
static struct tnode * fib_route_get_idx (struct fib_route_iter * iter , loff_t pos )
2195
2196
{
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 ;
2198
2201
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 ) {
2201
2204
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 );
2203
2209
iter -> pos = 0 ;
2204
- l = trie_firstleaf ( t ) ;
2210
+ key = 0 ;
2205
2211
}
2206
2212
2207
- while (l && pos -- > 0 ) {
2213
+ while ((l = leaf_walk_rcu (tp , key )) != NULL ) {
2214
+ key = l -> key + 1 ;
2208
2215
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 ;
2210
2225
}
2211
2226
2212
2227
if (l )
2213
- iter -> key = pos ; /* remember it */
2228
+ iter -> key = key ; /* remember it */
2214
2229
else
2215
2230
iter -> pos = 0 ; /* forget it */
2216
2231
@@ -2222,37 +2237,46 @@ static void *fib_route_seq_start(struct seq_file *seq, loff_t *pos)
2222
2237
{
2223
2238
struct fib_route_iter * iter = seq -> private ;
2224
2239
struct fib_table * tb ;
2240
+ struct trie * t ;
2225
2241
2226
2242
rcu_read_lock ();
2243
+
2227
2244
tb = fib_get_table (seq_file_net (seq ), RT_TABLE_MAIN );
2228
2245
if (!tb )
2229
2246
return NULL ;
2230
2247
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 ;
2236
2259
}
2237
2260
2238
2261
static void * fib_route_seq_next (struct seq_file * seq , void * v , loff_t * pos )
2239
2262
{
2240
2263
struct fib_route_iter * iter = seq -> private ;
2241
- struct tnode * l = v ;
2264
+ struct tnode * l = NULL ;
2265
+ t_key key = iter -> key ;
2242
2266
2243
2267
++ * 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 ;
2248
2275
iter -> pos ++ ;
2249
- l = trie_nextleaf (l );
2276
+ } else {
2277
+ iter -> pos = 0 ;
2250
2278
}
2251
2279
2252
- if (l )
2253
- iter -> key = l -> key ;
2254
- else
2255
- iter -> pos = 0 ;
2256
2280
return l ;
2257
2281
}
2258
2282
0 commit comments