aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/generic/patches-3.18/080-08-fib_trie-Optimize-fib_table_insert.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/generic/patches-3.18/080-08-fib_trie-Optimize-fib_table_insert.patch')
-rw-r--r--target/linux/generic/patches-3.18/080-08-fib_trie-Optimize-fib_table_insert.patch276
1 files changed, 276 insertions, 0 deletions
diff --git a/target/linux/generic/patches-3.18/080-08-fib_trie-Optimize-fib_table_insert.patch b/target/linux/generic/patches-3.18/080-08-fib_trie-Optimize-fib_table_insert.patch
new file mode 100644
index 0000000..b328d2c
--- /dev/null
+++ b/target/linux/generic/patches-3.18/080-08-fib_trie-Optimize-fib_table_insert.patch
@@ -0,0 +1,276 @@
+From: Alexander Duyck <alexander.h.duyck@redhat.com>
+Date: Wed, 31 Dec 2014 10:56:06 -0800
+Subject: [PATCH] fib_trie: Optimize fib_table_insert
+
+This patch updates the fib_table_insert function to take advantage of the
+changes made to improve the performance of fib_table_lookup. As a result
+the code should be smaller and run faster then the original.
+
+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
+@@ -222,31 +222,6 @@ static inline t_key tkey_extract_bits(t_
+ return 0;
+ }
+
+-static inline int tkey_equals(t_key a, t_key b)
+-{
+- return a == b;
+-}
+-
+-static inline int tkey_sub_equals(t_key a, int offset, int bits, t_key b)
+-{
+- if (bits == 0 || offset >= KEYLENGTH)
+- return 1;
+- bits = bits > KEYLENGTH ? KEYLENGTH : bits;
+- return ((a ^ b) << offset) >> (KEYLENGTH - bits) == 0;
+-}
+-
+-static inline int tkey_mismatch(t_key a, int offset, t_key b)
+-{
+- t_key diff = a ^ b;
+- int i = offset;
+-
+- if (!diff)
+- return 0;
+- while ((diff << i) >> (KEYLENGTH-1) == 0)
+- i++;
+- return i;
+-}
+-
+ /*
+ To understand this stuff, an understanding of keys and all their bits is
+ necessary. Every node in the trie has a key associated with it, but not
+@@ -485,6 +460,15 @@ static void tnode_put_child_reorg(struct
+ rcu_assign_pointer(tn->child[i], n);
+ }
+
++static void put_child_root(struct tnode *tp, struct trie *t,
++ t_key key, struct tnode *n)
++{
++ if (tp)
++ put_child(tp, get_index(key, tp), n);
++ else
++ rcu_assign_pointer(t->trie, n);
++}
++
+ #define MAX_WORK 10
+ static struct tnode *resize(struct trie *t, struct tnode *tn)
+ {
+@@ -959,138 +943,100 @@ static void trie_rebalance(struct trie *
+
+ static struct list_head *fib_insert_node(struct trie *t, u32 key, int plen)
+ {
+- int pos, newpos;
+- struct tnode *tp = NULL, *tn = NULL;
+- struct tnode *n;
+- struct tnode *l;
+- int missbit;
+ struct list_head *fa_head = NULL;
++ struct tnode *l, *n, *tp = NULL;
+ struct leaf_info *li;
+- t_key cindex;
+
+- pos = 0;
++ li = leaf_info_new(plen);
++ if (!li)
++ return NULL;
++ fa_head = &li->falh;
++
+ n = rtnl_dereference(t->trie);
+
+ /* If we point to NULL, stop. Either the tree is empty and we should
+ * just put a new leaf in if, or we have reached an empty child slot,
+ * and we should just put our new leaf in that.
+- * If we point to a T_TNODE, check if it matches our key. Note that
+- * a T_TNODE might be skipping any number of bits - its 'pos' need
+- * not be the parent's 'pos'+'bits'!
+- *
+- * If it does match the current key, get pos/bits from it, extract
+- * the index from our key, push the T_TNODE and walk the tree.
+- *
+- * If it doesn't, we have to replace it with a new T_TNODE.
+ *
+- * If we point to a T_LEAF, it might or might not have the same key
+- * as we do. If it does, just change the value, update the T_LEAF's
+- * value, and return it.
+- * If it doesn't, we need to replace it with a T_TNODE.
++ * If we hit a node with a key that does't match then we should stop
++ * and create a new tnode to replace that node and insert ourselves
++ * and the other node into the new tnode.
+ */
++ while (n) {
++ unsigned long index = get_index(key, n);
+
+- while (n && IS_TNODE(n)) {
+- if (tkey_sub_equals(n->key, pos, n->pos-pos, key)) {
+- tp = n;
+- pos = n->pos + n->bits;
+- n = tnode_get_child(n,
+- tkey_extract_bits(key,
+- n->pos,
+- n->bits));
+-
+- BUG_ON(n && node_parent(n) != tp);
+- } else
++ /* This bit of code is a bit tricky but it combines multiple
++ * checks into a single check. The prefix consists of the
++ * prefix plus zeros for the "bits" in the prefix. The index
++ * is the difference between the key and this value. From
++ * this we can actually derive several pieces of data.
++ * if !(index >> bits)
++ * we know the value is child index
++ * else
++ * we have a mismatch in skip bits and failed
++ */
++ if (index >> n->bits)
+ break;
+- }
+-
+- /*
+- * n ----> NULL, LEAF or TNODE
+- *
+- * tp is n's (parent) ----> NULL or TNODE
+- */
+
+- BUG_ON(tp && IS_LEAF(tp));
+-
+- /* Case 1: n is a leaf. Compare prefixes */
+-
+- if (n != NULL && IS_LEAF(n) && tkey_equals(key, n->key)) {
+- li = leaf_info_new(plen);
+-
+- if (!li)
+- return NULL;
++ /* we have found a leaf. Prefixes have already been compared */
++ if (IS_LEAF(n)) {
++ /* Case 1: n is a leaf, and prefixes match*/
++ insert_leaf_info(&n->list, li);
++ return fa_head;
++ }
+
+- fa_head = &li->falh;
+- insert_leaf_info(&n->list, li);
+- goto done;
++ tp = n;
++ n = rcu_dereference_rtnl(n->child[index]);
+ }
+- l = leaf_new(key);
+-
+- if (!l)
+- return NULL;
+
+- li = leaf_info_new(plen);
+-
+- if (!li) {
+- node_free(l);
++ l = leaf_new(key);
++ if (!l) {
++ free_leaf_info(li);
+ return NULL;
+ }
+
+- fa_head = &li->falh;
+ insert_leaf_info(&l->list, li);
+
+- if (t->trie && n == NULL) {
+- /* Case 2: n is NULL, and will just insert a new leaf */
+-
+- node_set_parent(l, tp);
+-
+- cindex = tkey_extract_bits(key, tp->pos, tp->bits);
+- put_child(tp, cindex, l);
+- } else {
+- /* Case 3: n is a LEAF or a TNODE and the key doesn't match. */
+- /*
+- * Add a new tnode here
+- * first tnode need some special handling
+- */
++ /* Case 2: n is a LEAF or a TNODE and the key doesn't match.
++ *
++ * Add a new tnode here
++ * first tnode need some special handling
++ * leaves us in position for handling as case 3
++ */
++ if (n) {
++ struct tnode *tn;
++ int newpos;
+
+- if (n) {
+- pos = tp ? tp->pos+tp->bits : 0;
+- newpos = tkey_mismatch(key, pos, n->key);
+- tn = tnode_new(n->key, newpos, 1);
+- } else {
+- newpos = 0;
+- tn = tnode_new(key, newpos, 1); /* First tnode */
+- }
++ newpos = KEYLENGTH - __fls(n->key ^ key) - 1;
+
++ tn = tnode_new(key, newpos, 1);
+ if (!tn) {
+ free_leaf_info(li);
+ node_free(l);
+ return NULL;
+ }
+
+- node_set_parent(tn, tp);
+-
+- missbit = tkey_extract_bits(key, newpos, 1);
+- put_child(tn, missbit, l);
+- put_child(tn, 1-missbit, n);
+-
+- if (tp) {
+- cindex = tkey_extract_bits(key, tp->pos, tp->bits);
+- put_child(tp, cindex, tn);
+- } else {
+- rcu_assign_pointer(t->trie, tn);
+- }
++ /* initialize routes out of node */
++ NODE_INIT_PARENT(tn, tp);
++ put_child(tn, get_index(key, tn) ^ 1, n);
++
++ /* start adding routes into the node */
++ put_child_root(tp, t, key, tn);
++ node_set_parent(n, tn);
+
++ /* parent now has a NULL spot where the leaf can go */
+ tp = tn;
+ }
+
+- if (tp && tp->pos + tp->bits > 32)
+- pr_warn("fib_trie tp=%p pos=%d, bits=%d, key=%0x plen=%d\n",
+- tp, tp->pos, tp->bits, key, plen);
+-
+- /* Rebalance the trie */
++ /* Case 3: n is NULL, and will just insert a new leaf */
++ if (tp) {
++ NODE_INIT_PARENT(l, tp);
++ put_child(tp, get_index(key, tp), l);
++ trie_rebalance(t, tp);
++ } else {
++ rcu_assign_pointer(t->trie, l);
++ }
+
+- trie_rebalance(t, tp);
+-done:
+ return fa_head;
+ }
+
+@@ -1470,11 +1416,11 @@ static void trie_leaf_remove(struct trie
+ pr_debug("entering trie_leaf_remove(%p)\n", l);
+
+ if (tp) {
+- t_key cindex = tkey_extract_bits(l->key, tp->pos, tp->bits);
+- put_child(tp, cindex, NULL);
++ put_child(tp, get_index(l->key, tp), NULL);
+ trie_rebalance(t, tp);
+- } else
++ } else {
+ RCU_INIT_POINTER(t->trie, NULL);
++ }
+
+ node_free(l);
+ }