net: Don't delete routes in different VRFs
When deleting an IP address from an interface, there is a clean-up of
routes which refer to this local address. However, there was no check to
see that the VRF matched. This meant that deletion wasn't confined to
the VRF it should have been.
To solve this, a new field has been added to fib_info to hold a table
id. When removing fib entries corresponding to a local ip address, this
table id is also used in the comparison.
The table id is populated when the fib_info is created. This was already
done in some places, but not in ip_rt_ioctl(). This has now been fixed.
Fixes: 021dd3b8a1
("net: Add routes to the table associated with the device")
Acked-by: David Ahern <dsa@cumulusnetworks.com>
Tested-by: David Ahern <dsa@cumulusnetworks.com>
Signed-off-by: Mark Tomlinson <mark.tomlinson@alliedtelesis.co.nz>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
daa7ee8dfa
commit
5a56a0b3a4
|
@ -111,6 +111,7 @@ struct fib_info {
|
||||||
unsigned char fib_scope;
|
unsigned char fib_scope;
|
||||||
unsigned char fib_type;
|
unsigned char fib_type;
|
||||||
__be32 fib_prefsrc;
|
__be32 fib_prefsrc;
|
||||||
|
u32 fib_tb_id;
|
||||||
u32 fib_priority;
|
u32 fib_priority;
|
||||||
u32 *fib_metrics;
|
u32 *fib_metrics;
|
||||||
#define fib_mtu fib_metrics[RTAX_MTU-1]
|
#define fib_mtu fib_metrics[RTAX_MTU-1]
|
||||||
|
@ -319,7 +320,7 @@ void fib_flush_external(struct net *net);
|
||||||
/* Exported by fib_semantics.c */
|
/* Exported by fib_semantics.c */
|
||||||
int ip_fib_check_default(__be32 gw, struct net_device *dev);
|
int ip_fib_check_default(__be32 gw, struct net_device *dev);
|
||||||
int fib_sync_down_dev(struct net_device *dev, unsigned long event, bool force);
|
int fib_sync_down_dev(struct net_device *dev, unsigned long event, bool force);
|
||||||
int fib_sync_down_addr(struct net *net, __be32 local);
|
int fib_sync_down_addr(struct net_device *dev, __be32 local);
|
||||||
int fib_sync_up(struct net_device *dev, unsigned int nh_flags);
|
int fib_sync_up(struct net_device *dev, unsigned int nh_flags);
|
||||||
|
|
||||||
extern u32 fib_multipath_secret __read_mostly;
|
extern u32 fib_multipath_secret __read_mostly;
|
||||||
|
|
|
@ -509,6 +509,7 @@ static int rtentry_to_fib_config(struct net *net, int cmd, struct rtentry *rt,
|
||||||
if (!dev)
|
if (!dev)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
cfg->fc_oif = dev->ifindex;
|
cfg->fc_oif = dev->ifindex;
|
||||||
|
cfg->fc_table = l3mdev_fib_table(dev);
|
||||||
if (colon) {
|
if (colon) {
|
||||||
struct in_ifaddr *ifa;
|
struct in_ifaddr *ifa;
|
||||||
struct in_device *in_dev = __in_dev_get_rtnl(dev);
|
struct in_device *in_dev = __in_dev_get_rtnl(dev);
|
||||||
|
@ -1027,7 +1028,7 @@ no_promotions:
|
||||||
* First of all, we scan fib_info list searching
|
* First of all, we scan fib_info list searching
|
||||||
* for stray nexthop entries, then ignite fib_flush.
|
* for stray nexthop entries, then ignite fib_flush.
|
||||||
*/
|
*/
|
||||||
if (fib_sync_down_addr(dev_net(dev), ifa->ifa_local))
|
if (fib_sync_down_addr(dev, ifa->ifa_local))
|
||||||
fib_flush(dev_net(dev));
|
fib_flush(dev_net(dev));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1057,6 +1057,7 @@ struct fib_info *fib_create_info(struct fib_config *cfg)
|
||||||
fi->fib_priority = cfg->fc_priority;
|
fi->fib_priority = cfg->fc_priority;
|
||||||
fi->fib_prefsrc = cfg->fc_prefsrc;
|
fi->fib_prefsrc = cfg->fc_prefsrc;
|
||||||
fi->fib_type = cfg->fc_type;
|
fi->fib_type = cfg->fc_type;
|
||||||
|
fi->fib_tb_id = cfg->fc_table;
|
||||||
|
|
||||||
fi->fib_nhs = nhs;
|
fi->fib_nhs = nhs;
|
||||||
change_nexthops(fi) {
|
change_nexthops(fi) {
|
||||||
|
@ -1337,18 +1338,21 @@ nla_put_failure:
|
||||||
* referring to it.
|
* referring to it.
|
||||||
* - device went down -> we must shutdown all nexthops going via it.
|
* - device went down -> we must shutdown all nexthops going via it.
|
||||||
*/
|
*/
|
||||||
int fib_sync_down_addr(struct net *net, __be32 local)
|
int fib_sync_down_addr(struct net_device *dev, __be32 local)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
unsigned int hash = fib_laddr_hashfn(local);
|
unsigned int hash = fib_laddr_hashfn(local);
|
||||||
struct hlist_head *head = &fib_info_laddrhash[hash];
|
struct hlist_head *head = &fib_info_laddrhash[hash];
|
||||||
|
struct net *net = dev_net(dev);
|
||||||
|
int tb_id = l3mdev_fib_table(dev);
|
||||||
struct fib_info *fi;
|
struct fib_info *fi;
|
||||||
|
|
||||||
if (!fib_info_laddrhash || local == 0)
|
if (!fib_info_laddrhash || local == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
hlist_for_each_entry(fi, head, fib_lhash) {
|
hlist_for_each_entry(fi, head, fib_lhash) {
|
||||||
if (!net_eq(fi->fib_net, net))
|
if (!net_eq(fi->fib_net, net) ||
|
||||||
|
fi->fib_tb_id != tb_id)
|
||||||
continue;
|
continue;
|
||||||
if (fi->fib_prefsrc == local) {
|
if (fi->fib_prefsrc == local) {
|
||||||
fi->fib_flags |= RTNH_F_DEAD;
|
fi->fib_flags |= RTNH_F_DEAD;
|
||||||
|
|
Loading…
Reference in New Issue