123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276 |
- 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);
- }
|