aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4
diff options
context:
space:
mode:
authorJulian Anastasov <ja@ssi.bg>2008-01-29 00:18:06 -0500
committerDavid S. Miller <davem@davemloft.net>2008-01-31 22:27:10 -0500
commit936f6f8e1bc46834bbb3e3fa3ac13ab44f1e7ba6 (patch)
tree7182107af01604a5516ba90e748dad16da3d1656 /net/ipv4
parentc18865f39276435abb9286f9a816cb5b66c99a00 (diff)
[IPV4] fib_trie: apply fixes from fib_hash
Update fib_trie with some fib_hash fixes: - check for duplicate alternative routes for prefix+tos+priority when replacing route - properly insert by matching tos together with priority - fix alias walking to use list_for_each_entry_continue for insertion and deletion when fa_head is not NULL - copy state from fa to new_fa on replace (not a problem for now) - additionally, avoid replacement without error if new route is same, as Joonwoo Park suggests. Signed-off-by: Julian Anastasov <ja@ssi.bg> Signed-off-by: David S. Miller <davem@davemloft.net>
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)