aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexander Duyck <alexander.h.duyck@redhat.com>2015-03-04 18:02:18 -0500
committerDavid S. Miller <davem@davemloft.net>2015-03-04 23:35:18 -0500
commitd5d6487cb8f019ab663df4c03519cd69e4362795 (patch)
tree3b91168ca403743d495175441b58da7273d21ba9
parentd4a975e83f4de2e454d7f937b36ce13b010c65ce (diff)
fib_trie: Update insert and delete to make use of tp from find_node
This change makes it so that the insert and delete functions make use of the tnode pointer returned in the fib_find_node call. By doing this we will not have to rely on the parent pointer in the leaf which will be going away soon. Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/ipv4/fib_trie.c237
1 files changed, 95 insertions, 142 deletions
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index 5d0f145dbafe..5be88df02b27 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -300,7 +300,7 @@ static inline void empty_child_dec(struct tnode *n)
300 n->empty_children-- ? : n->full_children--; 300 n->empty_children-- ? : n->full_children--;
301} 301}
302 302
303static struct tnode *leaf_new(t_key key) 303static struct tnode *leaf_new(t_key key, struct fib_alias *fa)
304{ 304{
305 struct tnode *l = kmem_cache_alloc(trie_leaf_kmem, GFP_KERNEL); 305 struct tnode *l = kmem_cache_alloc(trie_leaf_kmem, GFP_KERNEL);
306 if (l) { 306 if (l) {
@@ -310,12 +310,14 @@ static struct tnode *leaf_new(t_key key)
310 * as the nodes are searched 310 * as the nodes are searched
311 */ 311 */
312 l->key = key; 312 l->key = key;
313 l->slen = 0; 313 l->slen = fa->fa_slen;
314 l->pos = 0; 314 l->pos = 0;
315 /* set bits to 0 indicating we are not a tnode */ 315 /* set bits to 0 indicating we are not a tnode */
316 l->bits = 0; 316 l->bits = 0;
317 317
318 /* link leaf to fib alias */
318 INIT_HLIST_HEAD(&l->leaf); 319 INIT_HLIST_HEAD(&l->leaf);
320 hlist_add_head(&fa->fa_list, &l->leaf);
319 } 321 }
320 return l; 322 return l;
321} 323}
@@ -842,10 +844,8 @@ static void resize(struct trie *t, struct tnode *tn)
842 } 844 }
843} 845}
844 846
845static void leaf_pull_suffix(struct tnode *l) 847static void leaf_pull_suffix(struct tnode *tp, struct tnode *l)
846{ 848{
847 struct tnode *tp = node_parent(l);
848
849 while (tp && (tp->slen > tp->pos) && (tp->slen > l->slen)) { 849 while (tp && (tp->slen > tp->pos) && (tp->slen > l->slen)) {
850 if (update_suffix(tp) > l->slen) 850 if (update_suffix(tp) > l->slen)
851 break; 851 break;
@@ -853,10 +853,8 @@ static void leaf_pull_suffix(struct tnode *l)
853 } 853 }
854} 854}
855 855
856static void leaf_push_suffix(struct tnode *l) 856static void leaf_push_suffix(struct tnode *tn, struct tnode *l)
857{ 857{
858 struct tnode *tn = node_parent(l);
859
860 /* if this is a new leaf then tn will be NULL and we can sort 858 /* if this is a new leaf then tn will be NULL and we can sort
861 * out parent suffix lengths as a part of trie_rebalance 859 * out parent suffix lengths as a part of trie_rebalance
862 */ 860 */
@@ -866,51 +864,6 @@ static void leaf_push_suffix(struct tnode *l)
866 } 864 }
867} 865}
868 866
869static void fib_remove_alias(struct tnode *l, struct fib_alias *old)
870{
871 /* record the location of the previous list_info entry */
872 struct hlist_node **pprev = old->fa_list.pprev;
873 struct fib_alias *fa = hlist_entry(pprev, typeof(*fa), fa_list.next);
874
875 /* remove the fib_alias from the list */
876 hlist_del_rcu(&old->fa_list);
877
878 /* only access fa if it is pointing at the last valid hlist_node */
879 if (hlist_empty(&l->leaf) || (*pprev))
880 return;
881
882 /* update the trie with the latest suffix length */
883 l->slen = fa->fa_slen;
884 leaf_pull_suffix(l);
885}
886
887static void fib_insert_alias(struct tnode *l, struct fib_alias *fa,
888 struct fib_alias *new)
889{
890 if (fa) {
891 hlist_add_before_rcu(&new->fa_list, &fa->fa_list);
892 } else {
893 struct fib_alias *last;
894
895 hlist_for_each_entry(last, &l->leaf, fa_list) {
896 if (new->fa_slen < last->fa_slen)
897 break;
898 fa = last;
899 }
900
901 if (fa)
902 hlist_add_behind_rcu(&new->fa_list, &fa->fa_list);
903 else
904 hlist_add_head_rcu(&new->fa_list, &l->leaf);
905 }
906
907 /* if we added to the tail node then we need to update slen */
908 if (l->slen < new->fa_slen) {
909 l->slen = new->fa_slen;
910 leaf_push_suffix(l);
911 }
912}
913
914/* rcu_read_lock needs to be hold by caller from readside */ 867/* rcu_read_lock needs to be hold by caller from readside */
915static struct tnode *fib_find_node(struct trie *t, struct tnode **tn, u32 key) 868static struct tnode *fib_find_node(struct trie *t, struct tnode **tn, u32 key)
916{ 869{
@@ -980,61 +933,28 @@ static void trie_rebalance(struct trie *t, struct tnode *tn)
980{ 933{
981 struct tnode *tp; 934 struct tnode *tp;
982 935
983 while ((tp = node_parent(tn)) != NULL) { 936 while (tn) {
937 tp = node_parent(tn);
984 resize(t, tn); 938 resize(t, tn);
985 tn = tp; 939 tn = tp;
986 } 940 }
987
988 /* Handle last (top) tnode */
989 if (IS_TNODE(tn))
990 resize(t, tn);
991} 941}
992 942
993/* only used from updater-side */ 943/* only used from updater-side */
994 944static int fib_insert_node(struct trie *t, struct tnode *tp,
995static struct tnode *fib_insert_node(struct trie *t, u32 key, int plen) 945 struct fib_alias *new, t_key key)
996{ 946{
997 struct tnode *l, *n, *tp = NULL; 947 struct tnode *n, *l;
998
999 n = rtnl_dereference(t->trie);
1000
1001 /* If we point to NULL, stop. Either the tree is empty and we should
1002 * just put a new leaf in if, or we have reached an empty child slot,
1003 * and we should just put our new leaf in that.
1004 *
1005 * If we hit a node with a key that does't match then we should stop
1006 * and create a new tnode to replace that node and insert ourselves
1007 * and the other node into the new tnode.
1008 */
1009 while (n) {
1010 unsigned long index = get_index(key, n);
1011
1012 /* This bit of code is a bit tricky but it combines multiple
1013 * checks into a single check. The prefix consists of the
1014 * prefix plus zeros for the "bits" in the prefix. The index
1015 * is the difference between the key and this value. From
1016 * this we can actually derive several pieces of data.
1017 * if !(index >> bits)
1018 * we know the value is child index
1019 * else
1020 * we have a mismatch in skip bits and failed
1021 */
1022 if (index >> n->bits)
1023 break;
1024
1025 /* we have found a leaf. Prefixes have already been compared */
1026 if (IS_LEAF(n)) {
1027 /* Case 1: n is a leaf, and prefixes match*/
1028 return n;
1029 }
1030
1031 tp = n;
1032 n = tnode_get_child_rcu(n, index);
1033 }
1034 948
1035 l = leaf_new(key); 949 l = leaf_new(key, new);
1036 if (!l) 950 if (!l)
1037 return NULL; 951 return -ENOMEM;
952
953 /* retrieve child from parent node */
954 if (tp)
955 n = tnode_get_child(tp, get_index(key, tp));
956 else
957 n = rcu_dereference_rtnl(t->trie);
1038 958
1039 /* Case 2: n is a LEAF or a TNODE and the key doesn't match. 959 /* Case 2: n is a LEAF or a TNODE and the key doesn't match.
1040 * 960 *
@@ -1048,7 +968,7 @@ static struct tnode *fib_insert_node(struct trie *t, u32 key, int plen)
1048 tn = tnode_new(key, __fls(key ^ n->key), 1); 968 tn = tnode_new(key, __fls(key ^ n->key), 1);
1049 if (!tn) { 969 if (!tn) {
1050 node_free(l); 970 node_free(l);
1051 return NULL; 971 return -ENOMEM;
1052 } 972 }
1053 973
1054 /* initialize routes out of node */ 974 /* initialize routes out of node */
@@ -1064,20 +984,47 @@ static struct tnode *fib_insert_node(struct trie *t, u32 key, int plen)
1064 } 984 }
1065 985
1066 /* Case 3: n is NULL, and will just insert a new leaf */ 986 /* Case 3: n is NULL, and will just insert a new leaf */
1067 if (tp) { 987 NODE_INIT_PARENT(l, tp);
1068 NODE_INIT_PARENT(l, tp); 988 put_child_root(tp, t, key, l);
1069 put_child(tp, get_index(key, tp), l); 989 trie_rebalance(t, tp);
1070 trie_rebalance(t, tp); 990
991 return 0;
992}
993
994static int fib_insert_alias(struct trie *t, struct tnode *tp,
995 struct tnode *l, struct fib_alias *new,
996 struct fib_alias *fa, t_key key)
997{
998 if (!l)
999 return fib_insert_node(t, tp, new, key);
1000
1001 if (fa) {
1002 hlist_add_before_rcu(&new->fa_list, &fa->fa_list);
1071 } else { 1003 } else {
1072 rcu_assign_pointer(t->trie, l); 1004 struct fib_alias *last;
1005
1006 hlist_for_each_entry(last, &l->leaf, fa_list) {
1007 if (new->fa_slen < last->fa_slen)
1008 break;
1009 fa = last;
1010 }
1011
1012 if (fa)
1013 hlist_add_behind_rcu(&new->fa_list, &fa->fa_list);
1014 else
1015 hlist_add_head_rcu(&new->fa_list, &l->leaf);
1073 } 1016 }
1074 1017
1075 return l; 1018 /* if we added to the tail node then we need to update slen */
1019 if (l->slen < new->fa_slen) {
1020 l->slen = new->fa_slen;
1021 leaf_push_suffix(tp, l);
1022 }
1023
1024 return 0;
1076} 1025}
1077 1026
1078/* 1027/* Caller must hold RTNL. */
1079 * Caller must hold RTNL.
1080 */
1081int fib_table_insert(struct fib_table *tb, struct fib_config *cfg) 1028int fib_table_insert(struct fib_table *tb, struct fib_config *cfg)
1082{ 1029{
1083 struct trie *t = (struct trie *)tb->tb_data; 1030 struct trie *t = (struct trie *)tb->tb_data;
@@ -1205,19 +1152,13 @@ int fib_table_insert(struct fib_table *tb, struct fib_config *cfg)
1205 new_fa->fa_slen = slen; 1152 new_fa->fa_slen = slen;
1206 1153
1207 /* Insert new entry to the list. */ 1154 /* Insert new entry to the list. */
1208 if (!l) { 1155 err = fib_insert_alias(t, tp, l, new_fa, fa, key);
1209 l = fib_insert_node(t, key, plen); 1156 if (err)
1210 if (unlikely(!l)) { 1157 goto out_free_new_fa;
1211 err = -ENOMEM;
1212 goto out_free_new_fa;
1213 }
1214 }
1215 1158
1216 if (!plen) 1159 if (!plen)
1217 tb->tb_num_default++; 1160 tb->tb_num_default++;
1218 1161
1219 fib_insert_alias(l, fa, new_fa);
1220
1221 rt_cache_flush(cfg->fc_nlinfo.nl_net); 1162 rt_cache_flush(cfg->fc_nlinfo.nl_net);
1222 rtmsg_fib(RTM_NEWROUTE, htonl(key), new_fa, plen, tb->tb_id, 1163 rtmsg_fib(RTM_NEWROUTE, htonl(key), new_fa, plen, tb->tb_id,
1223 &cfg->fc_nlinfo, 0); 1164 &cfg->fc_nlinfo, 0);
@@ -1406,9 +1347,36 @@ found:
1406} 1347}
1407EXPORT_SYMBOL_GPL(fib_table_lookup); 1348EXPORT_SYMBOL_GPL(fib_table_lookup);
1408 1349
1409/* 1350static void fib_remove_alias(struct trie *t, struct tnode *tp,
1410 * Caller must hold RTNL. 1351 struct tnode *l, struct fib_alias *old)
1411 */ 1352{
1353 /* record the location of the previous list_info entry */
1354 struct hlist_node **pprev = old->fa_list.pprev;
1355 struct fib_alias *fa = hlist_entry(pprev, typeof(*fa), fa_list.next);
1356
1357 /* remove the fib_alias from the list */
1358 hlist_del_rcu(&old->fa_list);
1359
1360 /* if we emptied the list this leaf will be freed and we can sort
1361 * out parent suffix lengths as a part of trie_rebalance
1362 */
1363 if (hlist_empty(&l->leaf)) {
1364 put_child_root(tp, t, l->key, NULL);
1365 node_free(l);
1366 trie_rebalance(t, tp);
1367 return;
1368 }
1369
1370 /* only access fa if it is pointing at the last valid hlist_node */
1371 if (*pprev)
1372 return;
1373
1374 /* update the trie with the latest suffix length */
1375 l->slen = fa->fa_slen;
1376 leaf_pull_suffix(tp, l);
1377}
1378
1379/* Caller must hold RTNL. */
1412int fib_table_delete(struct fib_table *tb, struct fib_config *cfg) 1380int fib_table_delete(struct fib_table *tb, struct fib_config *cfg)
1413{ 1381{
1414 struct trie *t = (struct trie *) tb->tb_data; 1382 struct trie *t = (struct trie *) tb->tb_data;
@@ -1432,7 +1400,6 @@ int fib_table_delete(struct fib_table *tb, struct fib_config *cfg)
1432 return -ESRCH; 1400 return -ESRCH;
1433 1401
1434 fa = fib_find_alias(&l->leaf, slen, tos, 0); 1402 fa = fib_find_alias(&l->leaf, slen, tos, 0);
1435
1436 if (!fa) 1403 if (!fa)
1437 return -ESRCH; 1404 return -ESRCH;
1438 1405
@@ -1461,33 +1428,19 @@ int fib_table_delete(struct fib_table *tb, struct fib_config *cfg)
1461 if (!fa_to_delete) 1428 if (!fa_to_delete)
1462 return -ESRCH; 1429 return -ESRCH;
1463 1430
1464 fa = fa_to_delete; 1431 rtmsg_fib(RTM_DELROUTE, htonl(key), fa_to_delete, plen, tb->tb_id,
1465 rtmsg_fib(RTM_DELROUTE, htonl(key), fa, plen, tb->tb_id,
1466 &cfg->fc_nlinfo, 0); 1432 &cfg->fc_nlinfo, 0);
1467 1433
1468 fib_remove_alias(l, fa);
1469
1470 if (!plen) 1434 if (!plen)
1471 tb->tb_num_default--; 1435 tb->tb_num_default--;
1472 1436
1473 if (hlist_empty(&l->leaf)) { 1437 fib_remove_alias(t, tp, l, fa_to_delete);
1474 struct tnode *tp = node_parent(l);
1475
1476 if (tp) {
1477 put_child(tp, get_index(l->key, tp), NULL);
1478 trie_rebalance(t, tp);
1479 } else {
1480 RCU_INIT_POINTER(t->trie, NULL);
1481 }
1482
1483 node_free(l);
1484 }
1485 1438
1486 if (fa->fa_state & FA_S_ACCESSED) 1439 if (fa_to_delete->fa_state & FA_S_ACCESSED)
1487 rt_cache_flush(cfg->fc_nlinfo.nl_net); 1440 rt_cache_flush(cfg->fc_nlinfo.nl_net);
1488 1441
1489 fib_release_info(fa->fa_info); 1442 fib_release_info(fa_to_delete->fa_info);
1490 alias_free_mem_rcu(fa); 1443 alias_free_mem_rcu(fa_to_delete);
1491 return 0; 1444 return 0;
1492} 1445}
1493 1446
@@ -1626,7 +1579,7 @@ backtrace:
1626 put_child_root(pn, t, n->key, NULL); 1579 put_child_root(pn, t, n->key, NULL);
1627 node_free(n); 1580 node_free(n);
1628 } else { 1581 } else {
1629 leaf_pull_suffix(n); 1582 leaf_pull_suffix(pn, n);
1630 } 1583 }
1631 1584
1632 /* if trie is leaf only loop is completed */ 1585 /* if trie is leaf only loop is completed */