73 lines
		
	
	
		
			2.0 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			73 lines
		
	
	
		
			2.0 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
From: Alexander Duyck <alexander.h.duyck@redhat.com>
 | 
						|
Date: Wed, 10 Dec 2014 21:49:22 -0800
 | 
						|
Subject: [PATCH] fib_trie: Fix trie balancing issue if new node pushes down
 | 
						|
 existing node
 | 
						|
 | 
						|
This patch addresses an issue with the level compression of the fib_trie.
 | 
						|
Specifically in the case of adding a new leaf that triggers a new node to
 | 
						|
be added that takes the place of the old node.  The result is a trie where
 | 
						|
the 1 child tnode is on one side and one leaf is on the other which gives
 | 
						|
you a very deep trie.  Below is the script I used to generate a trie on
 | 
						|
dummy0 with a 10.X.X.X family of addresses.
 | 
						|
 | 
						|
  ip link add type dummy
 | 
						|
  ipval=184549374
 | 
						|
  bit=2
 | 
						|
  for i in `seq 1 23`
 | 
						|
  do
 | 
						|
    ifconfig dummy0:$bit $ipval/8
 | 
						|
    ipval=`expr $ipval - $bit`
 | 
						|
    bit=`expr $bit \* 2`
 | 
						|
  done
 | 
						|
  cat /proc/net/fib_triestat
 | 
						|
 | 
						|
Running the script before the patch:
 | 
						|
 | 
						|
	Local:
 | 
						|
		Aver depth:     10.82
 | 
						|
		Max depth:      23
 | 
						|
		Leaves:         29
 | 
						|
		Prefixes:       30
 | 
						|
		Internal nodes: 27
 | 
						|
		  1: 26  2: 1
 | 
						|
		Pointers: 56
 | 
						|
	Null ptrs: 1
 | 
						|
	Total size: 5  kB
 | 
						|
 | 
						|
After applying the patch and repeating:
 | 
						|
 | 
						|
	Local:
 | 
						|
		Aver depth:     4.72
 | 
						|
		Max depth:      9
 | 
						|
		Leaves:         29
 | 
						|
		Prefixes:       30
 | 
						|
		Internal nodes: 12
 | 
						|
		  1: 3  2: 2  3: 7
 | 
						|
		Pointers: 70
 | 
						|
	Null ptrs: 30
 | 
						|
	Total size: 4  kB
 | 
						|
 | 
						|
What this fix does is start the rebalance at the newly created tnode
 | 
						|
instead of at the parent tnode.  This way if there is a gap between the
 | 
						|
parent and the new node it doesn't prevent the new tnode from being
 | 
						|
coalesced with any pre-existing nodes that may have been pushed into one
 | 
						|
of the new nodes child branches.
 | 
						|
 | 
						|
Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com>
 | 
						|
Signed-off-by: David S. Miller <davem@davemloft.net>
 | 
						|
---
 | 
						|
 | 
						|
--- a/net/ipv4/fib_trie.c
 | 
						|
+++ b/net/ipv4/fib_trie.c
 | 
						|
@@ -1143,8 +1143,9 @@ static struct list_head *fib_insert_node
 | 
						|
 			put_child(tp, cindex, (struct rt_trie_node *)tn);
 | 
						|
 		} else {
 | 
						|
 			rcu_assign_pointer(t->trie, (struct rt_trie_node *)tn);
 | 
						|
-			tp = tn;
 | 
						|
 		}
 | 
						|
+
 | 
						|
+		tp = tn;
 | 
						|
 	}
 | 
						|
 
 | 
						|
 	if (tp && tp->pos + tp->bits > 32)
 |