aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4')
-rw-r--r--net/ipv4/fib_trie.c55
1 files changed, 35 insertions, 20 deletions
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index f2f47033f31f..cbccafde8238 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -1205,20 +1205,45 @@ static int fn_trie_insert(struct fib_table *tb, struct fib_config *cfg)
1205 * and we need to allocate a new one of those as well. 1205 * and we need to allocate a new one of those as well.
1206 */ 1206 */
1207 1207
1208 if (fa && fa->fa_info->fib_priority == fi->fib_priority) { 1208 if (fa && fa->fa_tos == tos &&
1209 struct fib_alias *fa_orig; 1209 fa->fa_info->fib_priority == fi->fib_priority) {
1210 struct fib_alias *fa_first, *fa_match;
1210 1211
1211 err = -EEXIST; 1212 err = -EEXIST;
1212 if (cfg->fc_nlflags & NLM_F_EXCL) 1213 if (cfg->fc_nlflags & NLM_F_EXCL)
1213 goto out; 1214 goto out;
1214 1215
1216 /* We have 2 goals:
1217 * 1. Find exact match for type, scope, fib_info to avoid
1218 * duplicate routes
1219 * 2. Find next 'fa' (or head), NLM_F_APPEND inserts before it
1220 */
1221 fa_match = NULL;
1222 fa_first = fa;
1223 fa = list_entry(fa->fa_list.prev, struct fib_alias, fa_list);
1224 list_for_each_entry_continue(fa, fa_head, fa_list) {
1225 if (fa->fa_tos != tos)
1226 break;
1227 if (fa->fa_info->fib_priority != fi->fib_priority)
1228 break;
1229 if (fa->fa_type == cfg->fc_type &&
1230 fa->fa_scope == cfg->fc_scope &&
1231 fa->fa_info == fi) {
1232 fa_match = fa;
1233 break;
1234 }
1235 }
1236
1215 if (cfg->fc_nlflags & NLM_F_REPLACE) { 1237 if (cfg->fc_nlflags & NLM_F_REPLACE) {
1216 struct fib_info *fi_drop; 1238 struct fib_info *fi_drop;
1217 u8 state; 1239 u8 state;
1218 1240
1219 if (fi->fib_treeref > 1) 1241 fa = fa_first;
1242 if (fa_match) {
1243 if (fa == fa_match)
1244 err = 0;
1220 goto out; 1245 goto out;
1221 1246 }
1222 err = -ENOBUFS; 1247 err = -ENOBUFS;
1223 new_fa = kmem_cache_alloc(fn_alias_kmem, GFP_KERNEL); 1248 new_fa = kmem_cache_alloc(fn_alias_kmem, GFP_KERNEL);
1224 if (new_fa == NULL) 1249 if (new_fa == NULL)
@@ -1230,7 +1255,7 @@ static int fn_trie_insert(struct fib_table *tb, struct fib_config *cfg)
1230 new_fa->fa_type = cfg->fc_type; 1255 new_fa->fa_type = cfg->fc_type;
1231 new_fa->fa_scope = cfg->fc_scope; 1256 new_fa->fa_scope = cfg->fc_scope;
1232 state = fa->fa_state; 1257 state = fa->fa_state;
1233 new_fa->fa_state &= ~FA_S_ACCESSED; 1258 new_fa->fa_state = state & ~FA_S_ACCESSED;
1234 1259
1235 list_replace_rcu(&fa->fa_list, &new_fa->fa_list); 1260 list_replace_rcu(&fa->fa_list, &new_fa->fa_list);
1236 alias_free_mem_rcu(fa); 1261 alias_free_mem_rcu(fa);
@@ -1247,20 +1272,11 @@ static int fn_trie_insert(struct fib_table *tb, struct fib_config *cfg)
1247 * uses the same scope, type, and nexthop 1272 * uses the same scope, type, and nexthop
1248 * information. 1273 * information.
1249 */ 1274 */
1250 fa_orig = fa; 1275 if (fa_match)
1251 list_for_each_entry(fa, fa_orig->fa_list.prev, fa_list) { 1276 goto out;
1252 if (fa->fa_tos != tos)
1253 break;
1254 if (fa->fa_info->fib_priority != fi->fib_priority)
1255 break;
1256 if (fa->fa_type == cfg->fc_type &&
1257 fa->fa_scope == cfg->fc_scope &&
1258 fa->fa_info == fi)
1259 goto out;
1260 }
1261 1277
1262 if (!(cfg->fc_nlflags & NLM_F_APPEND)) 1278 if (!(cfg->fc_nlflags & NLM_F_APPEND))
1263 fa = fa_orig; 1279 fa = fa_first;
1264 } 1280 }
1265 err = -ENOENT; 1281 err = -ENOENT;
1266 if (!(cfg->fc_nlflags & NLM_F_CREATE)) 1282 if (!(cfg->fc_nlflags & NLM_F_CREATE))
@@ -1600,9 +1616,8 @@ static int fn_trie_delete(struct fib_table *tb, struct fib_config *cfg)
1600 pr_debug("Deleting %08x/%d tos=%d t=%p\n", key, plen, tos, t); 1616 pr_debug("Deleting %08x/%d tos=%d t=%p\n", key, plen, tos, t);
1601 1617
1602 fa_to_delete = NULL; 1618 fa_to_delete = NULL;
1603 fa_head = fa->fa_list.prev; 1619 fa = list_entry(fa->fa_list.prev, struct fib_alias, fa_list);
1604 1620 list_for_each_entry_continue(fa, fa_head, fa_list) {
1605 list_for_each_entry(fa, fa_head, fa_list) {
1606 struct fib_info *fi = fa->fa_info; 1621 struct fib_info *fi = fa->fa_info;
1607 1622
1608 if (fa->fa_tos != tos) 1623 if (fa->fa_tos != tos)