Commit 0b51b517 authored by WANG Cong's avatar WANG Cong Committed by Kleber Sacilotto de Souza

bonding: avoid NETDEV_CHANGEMTU event when unregistering slave

BugLink: http://bugs.launchpad.net/bugs/1704102

As Hongjun/Nicolas summarized in their original patch:

"
When a device changes from one netns to another, it's first unregistered,
then the netns reference is updated and the dev is registered in the new
netns. Thus, when a slave moves to another netns, it is first
unregistered. This triggers a NETDEV_UNREGISTER event which is caught by
the bonding driver. The driver calls bond_release(), which calls
dev_set_mtu() and thus triggers NETDEV_CHANGEMTU (the device is still in
the old netns).
"

This is a very special case, because the device is being unregistered
no one should still care about the NETDEV_CHANGEMTU event triggered
at this point, we can avoid broadcasting this event on this path,
and avoid touching inetdev_event()/addrconf_notify() path.

It requires to export __dev_set_mtu() to bonding driver.
Reported-by: default avatarHongjun Li <hongjun.li@6wind.com>
Reported-by: default avatarNicolas Dichtel <nicolas.dichtel@6wind.com>
Cc: Jay Vosburgh <j.vosburgh@gmail.com>
Cc: Veaceslav Falico <vfalico@gmail.com>
Cc: Andy Gospodarek <andy@greyhouse.net>
Signed-off-by: default avatarCong Wang <xiyou.wangcong@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
(cherry picked from commit f51048c3)
Signed-off-by: default avatarJoseph Salisbury <joseph.salisbury@canonical.com>
Acked-by: default avatarStefan Bader <stefan.bader@canonical.com>
Acked-by: default avatarSeth Forshee <seth.forshee@canonical.com>
Signed-off-by: default avatarThadeu Lima de Souza Cascardo <cascardo@canonical.com>
parent 629463ed
...@@ -1793,7 +1793,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) ...@@ -1793,7 +1793,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
*/ */
static int __bond_release_one(struct net_device *bond_dev, static int __bond_release_one(struct net_device *bond_dev,
struct net_device *slave_dev, struct net_device *slave_dev,
bool all) bool all, bool unregister)
{ {
struct bonding *bond = netdev_priv(bond_dev); struct bonding *bond = netdev_priv(bond_dev);
struct slave *slave, *oldcurrent; struct slave *slave, *oldcurrent;
...@@ -1935,6 +1935,9 @@ static int __bond_release_one(struct net_device *bond_dev, ...@@ -1935,6 +1935,9 @@ static int __bond_release_one(struct net_device *bond_dev,
dev_set_mac_address(slave_dev, &addr); dev_set_mac_address(slave_dev, &addr);
} }
if (unregister)
__dev_set_mtu(slave_dev, slave->original_mtu);
else
dev_set_mtu(slave_dev, slave->original_mtu); dev_set_mtu(slave_dev, slave->original_mtu);
slave_dev->priv_flags &= ~IFF_BONDING; slave_dev->priv_flags &= ~IFF_BONDING;
...@@ -1947,7 +1950,7 @@ static int __bond_release_one(struct net_device *bond_dev, ...@@ -1947,7 +1950,7 @@ static int __bond_release_one(struct net_device *bond_dev,
/* A wrapper used because of ndo_del_link */ /* A wrapper used because of ndo_del_link */
int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
{ {
return __bond_release_one(bond_dev, slave_dev, false); return __bond_release_one(bond_dev, slave_dev, false, false);
} }
/* First release a slave and then destroy the bond if no more slaves are left. /* First release a slave and then destroy the bond if no more slaves are left.
...@@ -1959,7 +1962,7 @@ static int bond_release_and_destroy(struct net_device *bond_dev, ...@@ -1959,7 +1962,7 @@ static int bond_release_and_destroy(struct net_device *bond_dev,
struct bonding *bond = netdev_priv(bond_dev); struct bonding *bond = netdev_priv(bond_dev);
int ret; int ret;
ret = bond_release(bond_dev, slave_dev); ret = __bond_release_one(bond_dev, slave_dev, false, true);
if (ret == 0 && !bond_has_slaves(bond)) { if (ret == 0 && !bond_has_slaves(bond)) {
bond_dev->priv_flags |= IFF_DISABLE_NETPOLL; bond_dev->priv_flags |= IFF_DISABLE_NETPOLL;
netdev_info(bond_dev, "Destroying bond %s\n", netdev_info(bond_dev, "Destroying bond %s\n",
...@@ -3008,7 +3011,7 @@ static int bond_slave_netdev_event(unsigned long event, ...@@ -3008,7 +3011,7 @@ static int bond_slave_netdev_event(unsigned long event,
if (bond_dev->type != ARPHRD_ETHER) if (bond_dev->type != ARPHRD_ETHER)
bond_release_and_destroy(bond_dev, slave_dev); bond_release_and_destroy(bond_dev, slave_dev);
else else
bond_release(bond_dev, slave_dev); __bond_release_one(bond_dev, slave_dev, false, true);
break; break;
case NETDEV_UP: case NETDEV_UP:
case NETDEV_CHANGE: case NETDEV_CHANGE:
...@@ -4207,7 +4210,7 @@ static void bond_uninit(struct net_device *bond_dev) ...@@ -4207,7 +4210,7 @@ static void bond_uninit(struct net_device *bond_dev)
/* Release the bonded slaves */ /* Release the bonded slaves */
bond_for_each_slave(bond, slave, iter) bond_for_each_slave(bond, slave, iter)
__bond_release_one(bond_dev, slave->dev, true); __bond_release_one(bond_dev, slave->dev, true, true);
netdev_info(bond_dev, "Released all slaves\n"); netdev_info(bond_dev, "Released all slaves\n");
arr = rtnl_dereference(bond->slave_arr); arr = rtnl_dereference(bond->slave_arr);
......
...@@ -3149,6 +3149,7 @@ void __dev_notify_flags(struct net_device *, unsigned int old_flags, ...@@ -3149,6 +3149,7 @@ void __dev_notify_flags(struct net_device *, unsigned int old_flags,
int dev_change_name(struct net_device *, const char *); int dev_change_name(struct net_device *, const char *);
int dev_set_alias(struct net_device *, const char *, size_t); int dev_set_alias(struct net_device *, const char *, size_t);
int dev_change_net_namespace(struct net_device *, struct net *, const char *); int dev_change_net_namespace(struct net_device *, struct net *, const char *);
int __dev_set_mtu(struct net_device *, int);
int dev_set_mtu(struct net_device *, int); int dev_set_mtu(struct net_device *, int);
void dev_set_group(struct net_device *, int); void dev_set_group(struct net_device *, int);
int dev_set_mac_address(struct net_device *, struct sockaddr *); int dev_set_mac_address(struct net_device *, struct sockaddr *);
......
...@@ -6065,7 +6065,7 @@ int dev_change_flags(struct net_device *dev, unsigned int flags) ...@@ -6065,7 +6065,7 @@ int dev_change_flags(struct net_device *dev, unsigned int flags)
} }
EXPORT_SYMBOL(dev_change_flags); EXPORT_SYMBOL(dev_change_flags);
static int __dev_set_mtu(struct net_device *dev, int new_mtu) int __dev_set_mtu(struct net_device *dev, int new_mtu)
{ {
const struct net_device_ops *ops = dev->netdev_ops; const struct net_device_ops *ops = dev->netdev_ops;
...@@ -6075,6 +6075,7 @@ static int __dev_set_mtu(struct net_device *dev, int new_mtu) ...@@ -6075,6 +6075,7 @@ static int __dev_set_mtu(struct net_device *dev, int new_mtu)
dev->mtu = new_mtu; dev->mtu = new_mtu;
return 0; return 0;
} }
EXPORT_SYMBOL(__dev_set_mtu);
/** /**
* dev_set_mtu - Change maximum transfer unit * dev_set_mtu - Change maximum transfer unit
......
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