Commit c18865f3 authored by Julian Anastasov's avatar Julian Anastasov Committed by David S. Miller

[IPV4] fib: fix route replacement, fib_info is shared

fib_info can be shared by many route prefixes but we don't want
duplicate alternative routes for a prefix+tos+priority. Last change
was not correct to check fib_treeref because it accounts usage from
other prefixes. Additionally, avoid replacement without error if new
route is same, as Joonwoo Park suggests.
Signed-off-by: default avatarJulian Anastasov <ja@ssi.bg>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent ec9dbb1c
...@@ -424,19 +424,43 @@ static int fn_hash_insert(struct fib_table *tb, struct fib_config *cfg) ...@@ -424,19 +424,43 @@ static int fn_hash_insert(struct fib_table *tb, struct fib_config *cfg)
if (fa && fa->fa_tos == tos && if (fa && fa->fa_tos == tos &&
fa->fa_info->fib_priority == fi->fib_priority) { fa->fa_info->fib_priority == fi->fib_priority) {
struct fib_alias *fa_orig; struct fib_alias *fa_first, *fa_match;
err = -EEXIST; err = -EEXIST;
if (cfg->fc_nlflags & NLM_F_EXCL) if (cfg->fc_nlflags & NLM_F_EXCL)
goto out; goto out;
/* We have 2 goals:
* 1. Find exact match for type, scope, fib_info to avoid
* duplicate routes
* 2. Find next 'fa' (or head), NLM_F_APPEND inserts before it
*/
fa_match = NULL;
fa_first = fa;
fa = list_entry(fa->fa_list.prev, struct fib_alias, fa_list);
list_for_each_entry_continue(fa, &f->fn_alias, fa_list) {
if (fa->fa_tos != tos)
break;
if (fa->fa_info->fib_priority != fi->fib_priority)
break;
if (fa->fa_type == cfg->fc_type &&
fa->fa_scope == cfg->fc_scope &&
fa->fa_info == fi) {
fa_match = fa;
break;
}
}
if (cfg->fc_nlflags & NLM_F_REPLACE) { if (cfg->fc_nlflags & NLM_F_REPLACE) {
struct fib_info *fi_drop; struct fib_info *fi_drop;
u8 state; u8 state;
if (fi->fib_treeref > 1) fa = fa_first;
if (fa_match) {
if (fa == fa_match)
err = 0;
goto out; goto out;
}
write_lock_bh(&fib_hash_lock); write_lock_bh(&fib_hash_lock);
fi_drop = fa->fa_info; fi_drop = fa->fa_info;
fa->fa_info = fi; fa->fa_info = fi;
...@@ -459,20 +483,11 @@ static int fn_hash_insert(struct fib_table *tb, struct fib_config *cfg) ...@@ -459,20 +483,11 @@ static int fn_hash_insert(struct fib_table *tb, struct fib_config *cfg)
* uses the same scope, type, and nexthop * uses the same scope, type, and nexthop
* information. * information.
*/ */
fa_orig = fa; if (fa_match)
fa = list_entry(fa->fa_list.prev, struct fib_alias, fa_list); goto out;
list_for_each_entry_continue(fa, &f->fn_alias, fa_list) {
if (fa->fa_tos != tos)
break;
if (fa->fa_info->fib_priority != fi->fib_priority)
break;
if (fa->fa_type == cfg->fc_type &&
fa->fa_scope == cfg->fc_scope &&
fa->fa_info == fi)
goto out;
}
if (!(cfg->fc_nlflags & NLM_F_APPEND)) if (!(cfg->fc_nlflags & NLM_F_APPEND))
fa = fa_orig; fa = fa_first;
} }
err = -ENOENT; err = -ENOENT;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment