ipv4: Fix nexthop caching wrt. scoping.

Move the scope value out of the fib alias entries and into fib_info,
so that we always use the correct scope when recomputing the nexthop
cached source address.

Reported-by: Julian Anastasov <ja@ssi.bg>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2011-03-24 18:06:47 -07:00
parent 436c3b66ec
commit 37e826c513
4 changed files with 16 additions and 20 deletions

View File

@ -51,7 +51,6 @@ struct fib_nh {
struct fib_info *nh_parent; struct fib_info *nh_parent;
unsigned nh_flags; unsigned nh_flags;
unsigned char nh_scope; unsigned char nh_scope;
unsigned char nh_cfg_scope;
#ifdef CONFIG_IP_ROUTE_MULTIPATH #ifdef CONFIG_IP_ROUTE_MULTIPATH
int nh_weight; int nh_weight;
int nh_power; int nh_power;
@ -75,9 +74,10 @@ struct fib_info {
struct net *fib_net; struct net *fib_net;
int fib_treeref; int fib_treeref;
atomic_t fib_clntref; atomic_t fib_clntref;
int fib_dead;
unsigned fib_flags; unsigned fib_flags;
int fib_protocol; unsigned char fib_dead;
unsigned char fib_protocol;
unsigned char fib_scope;
__be32 fib_prefsrc; __be32 fib_prefsrc;
u32 fib_priority; u32 fib_priority;
u32 *fib_metrics; u32 *fib_metrics;

View File

@ -10,7 +10,6 @@ struct fib_alias {
struct fib_info *fa_info; struct fib_info *fa_info;
u8 fa_tos; u8 fa_tos;
u8 fa_type; u8 fa_type;
u8 fa_scope;
u8 fa_state; u8 fa_state;
struct rcu_head rcu; struct rcu_head rcu;
}; };
@ -29,7 +28,7 @@ extern void fib_release_info(struct fib_info *);
extern struct fib_info *fib_create_info(struct fib_config *cfg); extern struct fib_info *fib_create_info(struct fib_config *cfg);
extern int fib_nh_match(struct fib_config *cfg, struct fib_info *fi); extern int fib_nh_match(struct fib_config *cfg, struct fib_info *fi);
extern int fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event, extern int fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
u32 tb_id, u8 type, u8 scope, __be32 dst, u32 tb_id, u8 type, __be32 dst,
int dst_len, u8 tos, struct fib_info *fi, int dst_len, u8 tos, struct fib_info *fi,
unsigned int); unsigned int);
extern void rtmsg_fib(int event, __be32 key, struct fib_alias *fa, extern void rtmsg_fib(int event, __be32 key, struct fib_alias *fa,

View File

@ -222,7 +222,7 @@ static inline unsigned int fib_info_hashfn(const struct fib_info *fi)
unsigned int mask = (fib_info_hash_size - 1); unsigned int mask = (fib_info_hash_size - 1);
unsigned int val = fi->fib_nhs; unsigned int val = fi->fib_nhs;
val ^= fi->fib_protocol; val ^= (fi->fib_protocol << 8) | fi->fib_scope;
val ^= (__force u32)fi->fib_prefsrc; val ^= (__force u32)fi->fib_prefsrc;
val ^= fi->fib_priority; val ^= fi->fib_priority;
for_nexthops(fi) { for_nexthops(fi) {
@ -248,6 +248,7 @@ static struct fib_info *fib_find_info(const struct fib_info *nfi)
if (fi->fib_nhs != nfi->fib_nhs) if (fi->fib_nhs != nfi->fib_nhs)
continue; continue;
if (nfi->fib_protocol == fi->fib_protocol && if (nfi->fib_protocol == fi->fib_protocol &&
nfi->fib_scope == fi->fib_scope &&
nfi->fib_prefsrc == fi->fib_prefsrc && nfi->fib_prefsrc == fi->fib_prefsrc &&
nfi->fib_priority == fi->fib_priority && nfi->fib_priority == fi->fib_priority &&
memcmp(nfi->fib_metrics, fi->fib_metrics, memcmp(nfi->fib_metrics, fi->fib_metrics,
@ -328,7 +329,7 @@ void rtmsg_fib(int event, __be32 key, struct fib_alias *fa,
goto errout; goto errout;
err = fib_dump_info(skb, info->pid, seq, event, tb_id, err = fib_dump_info(skb, info->pid, seq, event, tb_id,
fa->fa_type, fa->fa_scope, key, dst_len, fa->fa_type, key, dst_len,
fa->fa_tos, fa->fa_info, nlm_flags); fa->fa_tos, fa->fa_info, nlm_flags);
if (err < 0) { if (err < 0) {
/* -EMSGSIZE implies BUG in fib_nlmsg_size() */ /* -EMSGSIZE implies BUG in fib_nlmsg_size() */
@ -699,7 +700,7 @@ __be32 fib_info_update_nh_saddr(struct net *net, struct fib_nh *nh)
{ {
nh->nh_saddr = inet_select_addr(nh->nh_dev, nh->nh_saddr = inet_select_addr(nh->nh_dev,
nh->nh_gw, nh->nh_gw,
nh->nh_cfg_scope); nh->nh_parent->fib_scope);
nh->nh_saddr_genid = atomic_read(&net->ipv4.dev_addr_genid); nh->nh_saddr_genid = atomic_read(&net->ipv4.dev_addr_genid);
return nh->nh_saddr; return nh->nh_saddr;
@ -763,6 +764,7 @@ struct fib_info *fib_create_info(struct fib_config *cfg)
fi->fib_net = hold_net(net); fi->fib_net = hold_net(net);
fi->fib_protocol = cfg->fc_protocol; fi->fib_protocol = cfg->fc_protocol;
fi->fib_scope = cfg->fc_scope;
fi->fib_flags = cfg->fc_flags; fi->fib_flags = cfg->fc_flags;
fi->fib_priority = cfg->fc_priority; fi->fib_priority = cfg->fc_priority;
fi->fib_prefsrc = cfg->fc_prefsrc; fi->fib_prefsrc = cfg->fc_prefsrc;
@ -864,7 +866,6 @@ struct fib_info *fib_create_info(struct fib_config *cfg)
} }
change_nexthops(fi) { change_nexthops(fi) {
nexthop_nh->nh_cfg_scope = cfg->fc_scope;
fib_info_update_nh_saddr(net, nexthop_nh); fib_info_update_nh_saddr(net, nexthop_nh);
} endfor_nexthops(fi) } endfor_nexthops(fi)
@ -914,7 +915,7 @@ failure:
} }
int fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event, int fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
u32 tb_id, u8 type, u8 scope, __be32 dst, int dst_len, u8 tos, u32 tb_id, u8 type, __be32 dst, int dst_len, u8 tos,
struct fib_info *fi, unsigned int flags) struct fib_info *fi, unsigned int flags)
{ {
struct nlmsghdr *nlh; struct nlmsghdr *nlh;
@ -936,7 +937,7 @@ int fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
NLA_PUT_U32(skb, RTA_TABLE, tb_id); NLA_PUT_U32(skb, RTA_TABLE, tb_id);
rtm->rtm_type = type; rtm->rtm_type = type;
rtm->rtm_flags = fi->fib_flags; rtm->rtm_flags = fi->fib_flags;
rtm->rtm_scope = scope; rtm->rtm_scope = fi->fib_scope;
rtm->rtm_protocol = fi->fib_protocol; rtm->rtm_protocol = fi->fib_protocol;
if (rtm->rtm_dst_len) if (rtm->rtm_dst_len)
@ -1092,7 +1093,7 @@ void fib_select_default(struct fib_result *res)
list_for_each_entry_rcu(fa, fa_head, fa_list) { list_for_each_entry_rcu(fa, fa_head, fa_list) {
struct fib_info *next_fi = fa->fa_info; struct fib_info *next_fi = fa->fa_info;
if (fa->fa_scope != res->scope || if (next_fi->fib_scope != res->scope ||
fa->fa_type != RTN_UNICAST) fa->fa_type != RTN_UNICAST)
continue; continue;

View File

@ -1245,7 +1245,6 @@ int fib_table_insert(struct fib_table *tb, struct fib_config *cfg)
if (fa->fa_info->fib_priority != fi->fib_priority) if (fa->fa_info->fib_priority != fi->fib_priority)
break; break;
if (fa->fa_type == cfg->fc_type && if (fa->fa_type == cfg->fc_type &&
fa->fa_scope == cfg->fc_scope &&
fa->fa_info == fi) { fa->fa_info == fi) {
fa_match = fa; fa_match = fa;
break; break;
@ -1271,7 +1270,6 @@ int fib_table_insert(struct fib_table *tb, struct fib_config *cfg)
new_fa->fa_tos = fa->fa_tos; new_fa->fa_tos = fa->fa_tos;
new_fa->fa_info = fi; new_fa->fa_info = fi;
new_fa->fa_type = cfg->fc_type; new_fa->fa_type = cfg->fc_type;
new_fa->fa_scope = cfg->fc_scope;
state = fa->fa_state; state = fa->fa_state;
new_fa->fa_state = state & ~FA_S_ACCESSED; new_fa->fa_state = state & ~FA_S_ACCESSED;
@ -1308,7 +1306,6 @@ int fib_table_insert(struct fib_table *tb, struct fib_config *cfg)
new_fa->fa_info = fi; new_fa->fa_info = fi;
new_fa->fa_tos = tos; new_fa->fa_tos = tos;
new_fa->fa_type = cfg->fc_type; new_fa->fa_type = cfg->fc_type;
new_fa->fa_scope = cfg->fc_scope;
new_fa->fa_state = 0; new_fa->fa_state = 0;
/* /*
* Insert new entry to the list. * Insert new entry to the list.
@ -1362,7 +1359,7 @@ static int check_leaf(struct fib_table *tb, struct trie *t, struct leaf *l,
if (fa->fa_tos && fa->fa_tos != flp->flowi4_tos) if (fa->fa_tos && fa->fa_tos != flp->flowi4_tos)
continue; continue;
if (fa->fa_scope < flp->flowi4_scope) if (fa->fa_info->fib_scope < flp->flowi4_scope)
continue; continue;
fib_alias_accessed(fa); fib_alias_accessed(fa);
err = fib_props[fa->fa_type].error; err = fib_props[fa->fa_type].error;
@ -1388,7 +1385,7 @@ static int check_leaf(struct fib_table *tb, struct trie *t, struct leaf *l,
res->prefixlen = plen; res->prefixlen = plen;
res->nh_sel = nhsel; res->nh_sel = nhsel;
res->type = fa->fa_type; res->type = fa->fa_type;
res->scope = fa->fa_scope; res->scope = fa->fa_info->fib_scope;
res->fi = fi; res->fi = fi;
res->table = tb; res->table = tb;
res->fa_head = &li->falh; res->fa_head = &li->falh;
@ -1664,7 +1661,7 @@ int fib_table_delete(struct fib_table *tb, struct fib_config *cfg)
if ((!cfg->fc_type || fa->fa_type == cfg->fc_type) && if ((!cfg->fc_type || fa->fa_type == cfg->fc_type) &&
(cfg->fc_scope == RT_SCOPE_NOWHERE || (cfg->fc_scope == RT_SCOPE_NOWHERE ||
fa->fa_scope == cfg->fc_scope) && fa->fa_info->fib_scope == cfg->fc_scope) &&
(!cfg->fc_prefsrc || (!cfg->fc_prefsrc ||
fi->fib_prefsrc == cfg->fc_prefsrc) && fi->fib_prefsrc == cfg->fc_prefsrc) &&
(!cfg->fc_protocol || (!cfg->fc_protocol ||
@ -1863,7 +1860,6 @@ static int fn_trie_dump_fa(t_key key, int plen, struct list_head *fah,
RTM_NEWROUTE, RTM_NEWROUTE,
tb->tb_id, tb->tb_id,
fa->fa_type, fa->fa_type,
fa->fa_scope,
xkey, xkey,
plen, plen,
fa->fa_tos, fa->fa_tos,
@ -2384,7 +2380,7 @@ static int fib_trie_seq_show(struct seq_file *seq, void *v)
seq_indent(seq, iter->depth+1); seq_indent(seq, iter->depth+1);
seq_printf(seq, " /%d %s %s", li->plen, seq_printf(seq, " /%d %s %s", li->plen,
rtn_scope(buf1, sizeof(buf1), rtn_scope(buf1, sizeof(buf1),
fa->fa_scope), fa->fa_info->fib_scope),
rtn_type(buf2, sizeof(buf2), rtn_type(buf2, sizeof(buf2),
fa->fa_type)); fa->fa_type));
if (fa->fa_tos) if (fa->fa_tos)