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>

+16 -20
+3 -3
include/net/ip_fib.h
··· 51 struct fib_info *nh_parent; 52 unsigned nh_flags; 53 unsigned char nh_scope; 54 - unsigned char nh_cfg_scope; 55 #ifdef CONFIG_IP_ROUTE_MULTIPATH 56 int nh_weight; 57 int nh_power; ··· 74 struct net *fib_net; 75 int fib_treeref; 76 atomic_t fib_clntref; 77 - int fib_dead; 78 unsigned fib_flags; 79 - int fib_protocol; 80 __be32 fib_prefsrc; 81 u32 fib_priority; 82 u32 *fib_metrics;
··· 51 struct fib_info *nh_parent; 52 unsigned nh_flags; 53 unsigned char nh_scope; 54 #ifdef CONFIG_IP_ROUTE_MULTIPATH 55 int nh_weight; 56 int nh_power; ··· 75 struct net *fib_net; 76 int fib_treeref; 77 atomic_t fib_clntref; 78 unsigned fib_flags; 79 + unsigned char fib_dead; 80 + unsigned char fib_protocol; 81 + unsigned char fib_scope; 82 __be32 fib_prefsrc; 83 u32 fib_priority; 84 u32 *fib_metrics;
+1 -2
net/ipv4/fib_lookup.h
··· 10 struct fib_info *fa_info; 11 u8 fa_tos; 12 u8 fa_type; 13 - u8 fa_scope; 14 u8 fa_state; 15 struct rcu_head rcu; 16 }; ··· 28 extern struct fib_info *fib_create_info(struct fib_config *cfg); 29 extern int fib_nh_match(struct fib_config *cfg, struct fib_info *fi); 30 extern int fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event, 31 - u32 tb_id, u8 type, u8 scope, __be32 dst, 32 int dst_len, u8 tos, struct fib_info *fi, 33 unsigned int); 34 extern void rtmsg_fib(int event, __be32 key, struct fib_alias *fa,
··· 10 struct fib_info *fa_info; 11 u8 fa_tos; 12 u8 fa_type; 13 u8 fa_state; 14 struct rcu_head rcu; 15 }; ··· 29 extern struct fib_info *fib_create_info(struct fib_config *cfg); 30 extern int fib_nh_match(struct fib_config *cfg, struct fib_info *fi); 31 extern int fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event, 32 + u32 tb_id, u8 type, __be32 dst, 33 int dst_len, u8 tos, struct fib_info *fi, 34 unsigned int); 35 extern void rtmsg_fib(int event, __be32 key, struct fib_alias *fa,
+8 -7
net/ipv4/fib_semantics.c
··· 222 unsigned int mask = (fib_info_hash_size - 1); 223 unsigned int val = fi->fib_nhs; 224 225 - val ^= fi->fib_protocol; 226 val ^= (__force u32)fi->fib_prefsrc; 227 val ^= fi->fib_priority; 228 for_nexthops(fi) { ··· 248 if (fi->fib_nhs != nfi->fib_nhs) 249 continue; 250 if (nfi->fib_protocol == fi->fib_protocol && 251 nfi->fib_prefsrc == fi->fib_prefsrc && 252 nfi->fib_priority == fi->fib_priority && 253 memcmp(nfi->fib_metrics, fi->fib_metrics, ··· 329 goto errout; 330 331 err = fib_dump_info(skb, info->pid, seq, event, tb_id, 332 - fa->fa_type, fa->fa_scope, key, dst_len, 333 fa->fa_tos, fa->fa_info, nlm_flags); 334 if (err < 0) { 335 /* -EMSGSIZE implies BUG in fib_nlmsg_size() */ ··· 700 { 701 nh->nh_saddr = inet_select_addr(nh->nh_dev, 702 nh->nh_gw, 703 - nh->nh_cfg_scope); 704 nh->nh_saddr_genid = atomic_read(&net->ipv4.dev_addr_genid); 705 706 return nh->nh_saddr; ··· 764 765 fi->fib_net = hold_net(net); 766 fi->fib_protocol = cfg->fc_protocol; 767 fi->fib_flags = cfg->fc_flags; 768 fi->fib_priority = cfg->fc_priority; 769 fi->fib_prefsrc = cfg->fc_prefsrc; ··· 866 } 867 868 change_nexthops(fi) { 869 - nexthop_nh->nh_cfg_scope = cfg->fc_scope; 870 fib_info_update_nh_saddr(net, nexthop_nh); 871 } endfor_nexthops(fi) 872 ··· 915 } 916 917 int fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event, 918 - u32 tb_id, u8 type, u8 scope, __be32 dst, int dst_len, u8 tos, 919 struct fib_info *fi, unsigned int flags) 920 { 921 struct nlmsghdr *nlh; ··· 937 NLA_PUT_U32(skb, RTA_TABLE, tb_id); 938 rtm->rtm_type = type; 939 rtm->rtm_flags = fi->fib_flags; 940 - rtm->rtm_scope = scope; 941 rtm->rtm_protocol = fi->fib_protocol; 942 943 if (rtm->rtm_dst_len) ··· 1093 list_for_each_entry_rcu(fa, fa_head, fa_list) { 1094 struct fib_info *next_fi = fa->fa_info; 1095 1096 - if (fa->fa_scope != res->scope || 1097 fa->fa_type != RTN_UNICAST) 1098 continue; 1099
··· 222 unsigned int mask = (fib_info_hash_size - 1); 223 unsigned int val = fi->fib_nhs; 224 225 + val ^= (fi->fib_protocol << 8) | fi->fib_scope; 226 val ^= (__force u32)fi->fib_prefsrc; 227 val ^= fi->fib_priority; 228 for_nexthops(fi) { ··· 248 if (fi->fib_nhs != nfi->fib_nhs) 249 continue; 250 if (nfi->fib_protocol == fi->fib_protocol && 251 + nfi->fib_scope == fi->fib_scope && 252 nfi->fib_prefsrc == fi->fib_prefsrc && 253 nfi->fib_priority == fi->fib_priority && 254 memcmp(nfi->fib_metrics, fi->fib_metrics, ··· 328 goto errout; 329 330 err = fib_dump_info(skb, info->pid, seq, event, tb_id, 331 + fa->fa_type, key, dst_len, 332 fa->fa_tos, fa->fa_info, nlm_flags); 333 if (err < 0) { 334 /* -EMSGSIZE implies BUG in fib_nlmsg_size() */ ··· 699 { 700 nh->nh_saddr = inet_select_addr(nh->nh_dev, 701 nh->nh_gw, 702 + nh->nh_parent->fib_scope); 703 nh->nh_saddr_genid = atomic_read(&net->ipv4.dev_addr_genid); 704 705 return nh->nh_saddr; ··· 763 764 fi->fib_net = hold_net(net); 765 fi->fib_protocol = cfg->fc_protocol; 766 + fi->fib_scope = cfg->fc_scope; 767 fi->fib_flags = cfg->fc_flags; 768 fi->fib_priority = cfg->fc_priority; 769 fi->fib_prefsrc = cfg->fc_prefsrc; ··· 864 } 865 866 change_nexthops(fi) { 867 fib_info_update_nh_saddr(net, nexthop_nh); 868 } endfor_nexthops(fi) 869 ··· 914 } 915 916 int fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event, 917 + u32 tb_id, u8 type, __be32 dst, int dst_len, u8 tos, 918 struct fib_info *fi, unsigned int flags) 919 { 920 struct nlmsghdr *nlh; ··· 936 NLA_PUT_U32(skb, RTA_TABLE, tb_id); 937 rtm->rtm_type = type; 938 rtm->rtm_flags = fi->fib_flags; 939 + rtm->rtm_scope = fi->fib_scope; 940 rtm->rtm_protocol = fi->fib_protocol; 941 942 if (rtm->rtm_dst_len) ··· 1092 list_for_each_entry_rcu(fa, fa_head, fa_list) { 1093 struct fib_info *next_fi = fa->fa_info; 1094 1095 + if (next_fi->fib_scope != res->scope || 1096 fa->fa_type != RTN_UNICAST) 1097 continue; 1098
+4 -8
net/ipv4/fib_trie.c
··· 1245 if (fa->fa_info->fib_priority != fi->fib_priority) 1246 break; 1247 if (fa->fa_type == cfg->fc_type && 1248 - fa->fa_scope == cfg->fc_scope && 1249 fa->fa_info == fi) { 1250 fa_match = fa; 1251 break; ··· 1270 new_fa->fa_tos = fa->fa_tos; 1271 new_fa->fa_info = fi; 1272 new_fa->fa_type = cfg->fc_type; 1273 - new_fa->fa_scope = cfg->fc_scope; 1274 state = fa->fa_state; 1275 new_fa->fa_state = state & ~FA_S_ACCESSED; 1276 ··· 1306 new_fa->fa_info = fi; 1307 new_fa->fa_tos = tos; 1308 new_fa->fa_type = cfg->fc_type; 1309 - new_fa->fa_scope = cfg->fc_scope; 1310 new_fa->fa_state = 0; 1311 /* 1312 * Insert new entry to the list. ··· 1359 1360 if (fa->fa_tos && fa->fa_tos != flp->flowi4_tos) 1361 continue; 1362 - if (fa->fa_scope < flp->flowi4_scope) 1363 continue; 1364 fib_alias_accessed(fa); 1365 err = fib_props[fa->fa_type].error; ··· 1385 res->prefixlen = plen; 1386 res->nh_sel = nhsel; 1387 res->type = fa->fa_type; 1388 - res->scope = fa->fa_scope; 1389 res->fi = fi; 1390 res->table = tb; 1391 res->fa_head = &li->falh; ··· 1661 1662 if ((!cfg->fc_type || fa->fa_type == cfg->fc_type) && 1663 (cfg->fc_scope == RT_SCOPE_NOWHERE || 1664 - fa->fa_scope == cfg->fc_scope) && 1665 (!cfg->fc_prefsrc || 1666 fi->fib_prefsrc == cfg->fc_prefsrc) && 1667 (!cfg->fc_protocol || ··· 1860 RTM_NEWROUTE, 1861 tb->tb_id, 1862 fa->fa_type, 1863 - fa->fa_scope, 1864 xkey, 1865 plen, 1866 fa->fa_tos, ··· 2380 seq_indent(seq, iter->depth+1); 2381 seq_printf(seq, " /%d %s %s", li->plen, 2382 rtn_scope(buf1, sizeof(buf1), 2383 - fa->fa_scope), 2384 rtn_type(buf2, sizeof(buf2), 2385 fa->fa_type)); 2386 if (fa->fa_tos)
··· 1245 if (fa->fa_info->fib_priority != fi->fib_priority) 1246 break; 1247 if (fa->fa_type == cfg->fc_type && 1248 fa->fa_info == fi) { 1249 fa_match = fa; 1250 break; ··· 1271 new_fa->fa_tos = fa->fa_tos; 1272 new_fa->fa_info = fi; 1273 new_fa->fa_type = cfg->fc_type; 1274 state = fa->fa_state; 1275 new_fa->fa_state = state & ~FA_S_ACCESSED; 1276 ··· 1308 new_fa->fa_info = fi; 1309 new_fa->fa_tos = tos; 1310 new_fa->fa_type = cfg->fc_type; 1311 new_fa->fa_state = 0; 1312 /* 1313 * Insert new entry to the list. ··· 1362 1363 if (fa->fa_tos && fa->fa_tos != flp->flowi4_tos) 1364 continue; 1365 + if (fa->fa_info->fib_scope < flp->flowi4_scope) 1366 continue; 1367 fib_alias_accessed(fa); 1368 err = fib_props[fa->fa_type].error; ··· 1388 res->prefixlen = plen; 1389 res->nh_sel = nhsel; 1390 res->type = fa->fa_type; 1391 + res->scope = fa->fa_info->fib_scope; 1392 res->fi = fi; 1393 res->table = tb; 1394 res->fa_head = &li->falh; ··· 1664 1665 if ((!cfg->fc_type || fa->fa_type == cfg->fc_type) && 1666 (cfg->fc_scope == RT_SCOPE_NOWHERE || 1667 + fa->fa_info->fib_scope == cfg->fc_scope) && 1668 (!cfg->fc_prefsrc || 1669 fi->fib_prefsrc == cfg->fc_prefsrc) && 1670 (!cfg->fc_protocol || ··· 1863 RTM_NEWROUTE, 1864 tb->tb_id, 1865 fa->fa_type, 1866 xkey, 1867 plen, 1868 fa->fa_tos, ··· 2384 seq_indent(seq, iter->depth+1); 2385 seq_printf(seq, " /%d %s %s", li->plen, 2386 rtn_scope(buf1, sizeof(buf1), 2387 + fa->fa_info->fib_scope), 2388 rtn_type(buf2, sizeof(buf2), 2389 fa->fa_type)); 2390 if (fa->fa_tos)