Commit 85326fa5 authored by Denis V. Lunev's avatar Denis V. Lunev Committed by David S. Miller

[IPV4]: fib_sync_down rework.

fib_sync_down can be called with an address and with a device. In
reality it is called either with address OR with a device. The
codepath inside is completely different, so lets separate it into two
calls for these two cases.
Signed-off-by: default avatarDenis V. Lunev <den@openvz.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 4b8aa9ab
...@@ -218,7 +218,8 @@ extern void fib_select_default(struct net *net, const struct flowi *flp, ...@@ -218,7 +218,8 @@ extern void fib_select_default(struct net *net, const struct flowi *flp,
/* Exported by fib_semantics.c */ /* Exported by fib_semantics.c */
extern int ip_fib_check_default(__be32 gw, struct net_device *dev); extern int ip_fib_check_default(__be32 gw, struct net_device *dev);
extern int fib_sync_down(__be32 local, struct net_device *dev, int force); extern int fib_sync_down_dev(struct net_device *dev, int force);
extern int fib_sync_down_addr(__be32 local);
extern int fib_sync_up(struct net_device *dev); extern int fib_sync_up(struct net_device *dev);
extern __be32 __fib_res_prefsrc(struct fib_result *res); extern __be32 __fib_res_prefsrc(struct fib_result *res);
extern void fib_select_multipath(const struct flowi *flp, struct fib_result *res); extern void fib_select_multipath(const struct flowi *flp, struct fib_result *res);
......
...@@ -808,7 +808,7 @@ static void fib_del_ifaddr(struct in_ifaddr *ifa) ...@@ -808,7 +808,7 @@ static void fib_del_ifaddr(struct in_ifaddr *ifa)
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(ifa->ifa_local, NULL, 0)) if (fib_sync_down_addr(ifa->ifa_local))
fib_flush(dev->nd_net); fib_flush(dev->nd_net);
} }
} }
...@@ -898,7 +898,7 @@ static void nl_fib_lookup_exit(struct net *net) ...@@ -898,7 +898,7 @@ static void nl_fib_lookup_exit(struct net *net)
static void fib_disable_ip(struct net_device *dev, int force) static void fib_disable_ip(struct net_device *dev, int force)
{ {
if (fib_sync_down(0, dev, force)) if (fib_sync_down_dev(dev, force))
fib_flush(dev->nd_net); fib_flush(dev->nd_net);
rt_cache_flush(0); rt_cache_flush(0);
arp_ifdown(dev); arp_ifdown(dev);
......
...@@ -1031,70 +1031,72 @@ int fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event, ...@@ -1031,70 +1031,72 @@ int fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
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(__be32 local)
int fib_sync_down(__be32 local, struct net_device *dev, int force)
{ {
int ret = 0; int ret = 0;
int scope = RT_SCOPE_NOWHERE; unsigned int hash = fib_laddr_hashfn(local);
struct hlist_head *head = &fib_info_laddrhash[hash];
if (force) struct hlist_node *node;
scope = -1; struct fib_info *fi;
if (local && fib_info_laddrhash) { if (fib_info_laddrhash == NULL || local == 0)
unsigned int hash = fib_laddr_hashfn(local); return 0;
struct hlist_head *head = &fib_info_laddrhash[hash];
struct hlist_node *node;
struct fib_info *fi;
hlist_for_each_entry(fi, node, head, fib_lhash) { hlist_for_each_entry(fi, node, head, fib_lhash) {
if (fi->fib_prefsrc == local) { if (fi->fib_prefsrc == local) {
fi->fib_flags |= RTNH_F_DEAD; fi->fib_flags |= RTNH_F_DEAD;
ret++; ret++;
}
} }
} }
return ret;
}
if (dev) { int fib_sync_down_dev(struct net_device *dev, int force)
struct fib_info *prev_fi = NULL; {
unsigned int hash = fib_devindex_hashfn(dev->ifindex); int ret = 0;
struct hlist_head *head = &fib_info_devhash[hash]; int scope = RT_SCOPE_NOWHERE;
struct hlist_node *node; struct fib_info *prev_fi = NULL;
struct fib_nh *nh; unsigned int hash = fib_devindex_hashfn(dev->ifindex);
struct hlist_head *head = &fib_info_devhash[hash];
struct hlist_node *node;
struct fib_nh *nh;
hlist_for_each_entry(nh, node, head, nh_hash) { if (force)
struct fib_info *fi = nh->nh_parent; scope = -1;
int dead;
BUG_ON(!fi->fib_nhs); hlist_for_each_entry(nh, node, head, nh_hash) {
if (nh->nh_dev != dev || fi == prev_fi) struct fib_info *fi = nh->nh_parent;
continue; int dead;
prev_fi = fi;
dead = 0; BUG_ON(!fi->fib_nhs);
change_nexthops(fi) { if (nh->nh_dev != dev || fi == prev_fi)
if (nh->nh_flags&RTNH_F_DEAD) continue;
dead++; prev_fi = fi;
else if (nh->nh_dev == dev && dead = 0;
nh->nh_scope != scope) { change_nexthops(fi) {
nh->nh_flags |= RTNH_F_DEAD; if (nh->nh_flags&RTNH_F_DEAD)
dead++;
else if (nh->nh_dev == dev &&
nh->nh_scope != scope) {
nh->nh_flags |= RTNH_F_DEAD;
#ifdef CONFIG_IP_ROUTE_MULTIPATH #ifdef CONFIG_IP_ROUTE_MULTIPATH
spin_lock_bh(&fib_multipath_lock); spin_lock_bh(&fib_multipath_lock);
fi->fib_power -= nh->nh_power; fi->fib_power -= nh->nh_power;
nh->nh_power = 0; nh->nh_power = 0;
spin_unlock_bh(&fib_multipath_lock); spin_unlock_bh(&fib_multipath_lock);
#endif #endif
dead++; dead++;
} }
#ifdef CONFIG_IP_ROUTE_MULTIPATH #ifdef CONFIG_IP_ROUTE_MULTIPATH
if (force > 1 && nh->nh_dev == dev) { if (force > 1 && nh->nh_dev == dev) {
dead = fi->fib_nhs; dead = fi->fib_nhs;
break; break;
}
#endif
} endfor_nexthops(fi)
if (dead == fi->fib_nhs) {
fi->fib_flags |= RTNH_F_DEAD;
ret++;
} }
#endif
} endfor_nexthops(fi)
if (dead == fi->fib_nhs) {
fi->fib_flags |= RTNH_F_DEAD;
ret++;
} }
} }
......
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