aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4
diff options
context:
space:
mode:
authorAlexander Duyck <alexander.h.duyck@redhat.com>2015-03-12 17:46:29 -0400
committerDavid S. Miller <davem@davemloft.net>2015-03-12 18:26:51 -0400
commit0b65bd97ba5fc2c43fa4d077e7420f3ec09a40b3 (patch)
treec3b581a4c65b4e1dcad5f76138c252608c558360 /net/ipv4
parent3c9e9f7320f0138497ef7879c0903246746e0ed3 (diff)
fib_trie: Provide a deterministic order for fib_alias w/ tables merged
This change makes it so that we should always have a deterministic ordering for the main and local aliases within the merged table when two leaves overlap. So for example if we have a leaf with a key of 192.168.254.0. If we previously added two aliases with a prefix length of 24 from both local and main the first entry would be first and the second would be second. When I was coding this I had added a WARN_ON should such a situation occur as I wasn't sure how likely it would be. However this WARN_ON has been triggered so this is something that should be addressed. With this patch the ordering of the aliases is as follows. First they are sorted on prefix length, then on their table ID, then tos, and finally priority. This way what we end up doing is essentially interleaving the two tables on what used to be leaf_info structure boundaries. Fixes: 0ddcf43d5 ("ipv4: FIB Local/MAIN table collapse") Reported-by: Eric Dumazet <edumazet@google.com> Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4')
-rw-r--r--net/ipv4/fib_trie.c28
1 files changed, 17 insertions, 11 deletions
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index dd488c102d89..e3b4aee4244e 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -950,7 +950,7 @@ static struct key_vector *fib_find_node(struct trie *t,
950 * priority less than or equal to PRIO. 950 * priority less than or equal to PRIO.
951 */ 951 */
952static struct fib_alias *fib_find_alias(struct hlist_head *fah, u8 slen, 952static struct fib_alias *fib_find_alias(struct hlist_head *fah, u8 slen,
953 u8 tos, u32 prio) 953 u8 tos, u32 prio, u32 tb_id)
954{ 954{
955 struct fib_alias *fa; 955 struct fib_alias *fa;
956 956
@@ -962,6 +962,10 @@ static struct fib_alias *fib_find_alias(struct hlist_head *fah, u8 slen,
962 continue; 962 continue;
963 if (fa->fa_slen != slen) 963 if (fa->fa_slen != slen)
964 break; 964 break;
965 if (fa->tb_id > tb_id)
966 continue;
967 if (fa->tb_id != tb_id)
968 break;
965 if (fa->fa_tos > tos) 969 if (fa->fa_tos > tos)
966 continue; 970 continue;
967 if (fa->fa_info->fib_priority >= prio || fa->fa_tos < tos) 971 if (fa->fa_info->fib_priority >= prio || fa->fa_tos < tos)
@@ -1041,6 +1045,9 @@ static int fib_insert_alias(struct trie *t, struct key_vector *tp,
1041 hlist_for_each_entry(last, &l->leaf, fa_list) { 1045 hlist_for_each_entry(last, &l->leaf, fa_list) {
1042 if (new->fa_slen < last->fa_slen) 1046 if (new->fa_slen < last->fa_slen)
1043 break; 1047 break;
1048 if ((new->fa_slen == last->fa_slen) &&
1049 (new->tb_id > last->tb_id))
1050 break;
1044 fa = last; 1051 fa = last;
1045 } 1052 }
1046 1053
@@ -1089,7 +1096,8 @@ int fib_table_insert(struct fib_table *tb, struct fib_config *cfg)
1089 } 1096 }
1090 1097
1091 l = fib_find_node(t, &tp, key); 1098 l = fib_find_node(t, &tp, key);
1092 fa = l ? fib_find_alias(&l->leaf, slen, tos, fi->fib_priority) : NULL; 1099 fa = l ? fib_find_alias(&l->leaf, slen, tos, fi->fib_priority,
1100 tb->tb_id) : NULL;
1093 1101
1094 /* Now fa, if non-NULL, points to the first fib alias 1102 /* Now fa, if non-NULL, points to the first fib alias
1095 * with the same keys [prefix,tos,priority], if such key already 1103 * with the same keys [prefix,tos,priority], if such key already
@@ -1116,13 +1124,12 @@ int fib_table_insert(struct fib_table *tb, struct fib_config *cfg)
1116 fa_match = NULL; 1124 fa_match = NULL;
1117 fa_first = fa; 1125 fa_first = fa;
1118 hlist_for_each_entry_from(fa, fa_list) { 1126 hlist_for_each_entry_from(fa, fa_list) {
1119 if ((fa->fa_slen != slen) || (fa->fa_tos != tos)) 1127 if ((fa->fa_slen != slen) ||
1128 (fa->tb_id != tb->tb_id) ||
1129 (fa->fa_tos != tos))
1120 break; 1130 break;
1121 if (fa->fa_info->fib_priority != fi->fib_priority) 1131 if (fa->fa_info->fib_priority != fi->fib_priority)
1122 break; 1132 break;
1123 /* duplicate entry from another table */
1124 if (WARN_ON(fa->tb_id != tb->tb_id))
1125 continue;
1126 if (fa->fa_type == cfg->fc_type && 1133 if (fa->fa_type == cfg->fc_type &&
1127 fa->fa_info == fi) { 1134 fa->fa_info == fi) {
1128 fa_match = fa; 1135 fa_match = fa;
@@ -1474,7 +1481,7 @@ int fib_table_delete(struct fib_table *tb, struct fib_config *cfg)
1474 if (!l) 1481 if (!l)
1475 return -ESRCH; 1482 return -ESRCH;
1476 1483
1477 fa = fib_find_alias(&l->leaf, slen, tos, 0); 1484 fa = fib_find_alias(&l->leaf, slen, tos, 0, tb->tb_id);
1478 if (!fa) 1485 if (!fa)
1479 return -ESRCH; 1486 return -ESRCH;
1480 1487
@@ -1484,12 +1491,11 @@ int fib_table_delete(struct fib_table *tb, struct fib_config *cfg)
1484 hlist_for_each_entry_from(fa, fa_list) { 1491 hlist_for_each_entry_from(fa, fa_list) {
1485 struct fib_info *fi = fa->fa_info; 1492 struct fib_info *fi = fa->fa_info;
1486 1493
1487 if ((fa->fa_slen != slen) || (fa->fa_tos != tos)) 1494 if ((fa->fa_slen != slen) ||
1495 (fa->tb_id != tb->tb_id) ||
1496 (fa->fa_tos != tos))
1488 break; 1497 break;
1489 1498
1490 if (fa->tb_id != tb->tb_id)
1491 continue;
1492
1493 if ((!cfg->fc_type || fa->fa_type == cfg->fc_type) && 1499 if ((!cfg->fc_type || fa->fa_type == cfg->fc_type) &&
1494 (cfg->fc_scope == RT_SCOPE_NOWHERE || 1500 (cfg->fc_scope == RT_SCOPE_NOWHERE ||
1495 fa->fa_info->fib_scope == cfg->fc_scope) && 1501 fa->fa_info->fib_scope == cfg->fc_scope) &&