summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/bonding/bond_main.c9
-rw-r--r--include/linux/igmp.h2
-rw-r--r--include/linux/netdevice.h3
-rw-r--r--include/linux/notifier.h2
-rw-r--r--include/net/addrconf.h2
-rw-r--r--net/core/dev.c4
-rw-r--r--net/ipv4/devinet.c6
-rw-r--r--net/ipv4/igmp.c22
-rw-r--r--net/ipv6/addrconf.c19
-rw-r--r--net/ipv6/mcast.c19
10 files changed, 82 insertions, 6 deletions
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index a7e731f8a0d..6419cf9a4fa 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -1211,7 +1211,7 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
write_unlock_bh(&bond->curr_slave_lock);
read_unlock(&bond->lock);
- netdev_bonding_change(bond->dev);
+ netdev_bonding_change(bond->dev, NETDEV_BONDING_FAILOVER);
read_lock(&bond->lock);
write_lock_bh(&bond->curr_slave_lock);
@@ -1469,14 +1469,17 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
*/
if (bond->slave_cnt == 0) {
if (bond_dev->type != slave_dev->type) {
- dev_close(bond_dev);
pr_debug("%s: change device type from %d to %d\n",
bond_dev->name, bond_dev->type, slave_dev->type);
+
+ netdev_bonding_change(bond_dev, NETDEV_BONDING_OLDTYPE);
+
if (slave_dev->type != ARPHRD_ETHER)
bond_setup_by_slave(bond_dev, slave_dev);
else
ether_setup(bond_dev);
- dev_open(bond_dev);
+
+ netdev_bonding_change(bond_dev, NETDEV_BONDING_NEWTYPE);
}
} else if (bond_dev->type != slave_dev->type) {
pr_err(DRV_NAME ": %s ether type (%d) is different "
diff --git a/include/linux/igmp.h b/include/linux/igmp.h
index 92fbd8cbd68..fe158e0e20e 100644
--- a/include/linux/igmp.h
+++ b/include/linux/igmp.h
@@ -233,6 +233,8 @@ extern void ip_mc_init_dev(struct in_device *);
extern void ip_mc_destroy_dev(struct in_device *);
extern void ip_mc_up(struct in_device *);
extern void ip_mc_down(struct in_device *);
+extern void ip_mc_unmap(struct in_device *);
+extern void ip_mc_remap(struct in_device *);
extern void ip_mc_dec_group(struct in_device *in_dev, __be32 addr);
extern void ip_mc_inc_group(struct in_device *in_dev, __be32 addr);
extern void ip_mc_rejoin_group(struct ip_mc_list *im);
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 65ee1929b2b..f46db6c7a73 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1873,7 +1873,8 @@ extern void __dev_addr_unsync(struct dev_addr_list **to, int *to_count, struct
extern int dev_set_promiscuity(struct net_device *dev, int inc);
extern int dev_set_allmulti(struct net_device *dev, int inc);
extern void netdev_state_change(struct net_device *dev);
-extern void netdev_bonding_change(struct net_device *dev);
+extern void netdev_bonding_change(struct net_device *dev,
+ unsigned long event);
extern void netdev_features_change(struct net_device *dev);
/* Load a device via the kmod */
extern void dev_load(struct net *net, const char *name);
diff --git a/include/linux/notifier.h b/include/linux/notifier.h
index 81bc252dc8a..44428d247db 100644
--- a/include/linux/notifier.h
+++ b/include/linux/notifier.h
@@ -199,6 +199,8 @@ static inline int notifier_to_errno(int ret)
#define NETDEV_FEAT_CHANGE 0x000B
#define NETDEV_BONDING_FAILOVER 0x000C
#define NETDEV_PRE_UP 0x000D
+#define NETDEV_BONDING_OLDTYPE 0x000E
+#define NETDEV_BONDING_NEWTYPE 0x000F
#define SYS_DOWN 0x0001 /* Notify of system down */
#define SYS_RESTART SYS_DOWN
diff --git a/include/net/addrconf.h b/include/net/addrconf.h
index 7b55ab215a6..0f7c37825fc 100644
--- a/include/net/addrconf.h
+++ b/include/net/addrconf.h
@@ -143,6 +143,8 @@ extern int __ipv6_dev_mc_dec(struct inet6_dev *idev, const struct in6_addr *addr
extern int ipv6_dev_mc_dec(struct net_device *dev, const struct in6_addr *addr);
extern void ipv6_mc_up(struct inet6_dev *idev);
extern void ipv6_mc_down(struct inet6_dev *idev);
+extern void ipv6_mc_unmap(struct inet6_dev *idev);
+extern void ipv6_mc_remap(struct inet6_dev *idev);
extern void ipv6_mc_init_dev(struct inet6_dev *idev);
extern void ipv6_mc_destroy_dev(struct inet6_dev *idev);
extern void addrconf_dad_failure(struct inet6_ifaddr *ifp);
diff --git a/net/core/dev.c b/net/core/dev.c
index 84945470ab3..560c8c9c03a 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1017,9 +1017,9 @@ void netdev_state_change(struct net_device *dev)
}
EXPORT_SYMBOL(netdev_state_change);
-void netdev_bonding_change(struct net_device *dev)
+void netdev_bonding_change(struct net_device *dev, unsigned long event)
{
- call_netdevice_notifiers(NETDEV_BONDING_FAILOVER, dev);
+ call_netdevice_notifiers(event, dev);
}
EXPORT_SYMBOL(netdev_bonding_change);
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index 3863c3a4223..07336c6201f 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -1087,6 +1087,12 @@ static int inetdev_event(struct notifier_block *this, unsigned long event,
case NETDEV_DOWN:
ip_mc_down(in_dev);
break;
+ case NETDEV_BONDING_OLDTYPE:
+ ip_mc_unmap(in_dev);
+ break;
+ case NETDEV_BONDING_NEWTYPE:
+ ip_mc_remap(in_dev);
+ break;
case NETDEV_CHANGEMTU:
if (inetdev_valid_mtu(dev->mtu))
break;
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index 01b4284ed69..d41e5de79a8 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -1298,6 +1298,28 @@ void ip_mc_dec_group(struct in_device *in_dev, __be32 addr)
}
}
+/* Device changing type */
+
+void ip_mc_unmap(struct in_device *in_dev)
+{
+ struct ip_mc_list *i;
+
+ ASSERT_RTNL();
+
+ for (i = in_dev->mc_list; i; i = i->next)
+ igmp_group_dropped(i);
+}
+
+void ip_mc_remap(struct in_device *in_dev)
+{
+ struct ip_mc_list *i;
+
+ ASSERT_RTNL();
+
+ for (i = in_dev->mc_list; i; i = i->next)
+ igmp_group_added(i);
+}
+
/* Device going down */
void ip_mc_down(struct in_device *in_dev)
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index c9b369034a4..f216a41ceb2 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -137,6 +137,8 @@ static DEFINE_SPINLOCK(addrconf_verify_lock);
static void addrconf_join_anycast(struct inet6_ifaddr *ifp);
static void addrconf_leave_anycast(struct inet6_ifaddr *ifp);
+static void addrconf_bonding_change(struct net_device *dev,
+ unsigned long event);
static int addrconf_ifdown(struct net_device *dev, int how);
static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags);
@@ -2582,6 +2584,10 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
return notifier_from_errno(err);
}
break;
+ case NETDEV_BONDING_OLDTYPE:
+ case NETDEV_BONDING_NEWTYPE:
+ addrconf_bonding_change(dev, event);
+ break;
}
return NOTIFY_OK;
@@ -2595,6 +2601,19 @@ static struct notifier_block ipv6_dev_notf = {
.priority = 0
};
+static void addrconf_bonding_change(struct net_device *dev, unsigned long event)
+{
+ struct inet6_dev *idev;
+ ASSERT_RTNL();
+
+ idev = __in6_dev_get(dev);
+
+ if (event == NETDEV_BONDING_NEWTYPE)
+ ipv6_mc_remap(idev);
+ else if (event == NETDEV_BONDING_OLDTYPE)
+ ipv6_mc_unmap(idev);
+}
+
static int addrconf_ifdown(struct net_device *dev, int how)
{
struct inet6_dev *idev;
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index 71c3dacec1e..f9fcf690bd5 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -2249,6 +2249,25 @@ static void igmp6_timer_handler(unsigned long data)
ma_put(ma);
}
+/* Device changing type */
+
+void ipv6_mc_unmap(struct inet6_dev *idev)
+{
+ struct ifmcaddr6 *i;
+
+ /* Install multicast list, except for all-nodes (already installed) */
+
+ read_lock_bh(&idev->lock);
+ for (i = idev->mc_list; i; i = i->next)
+ igmp6_group_dropped(i);
+ read_unlock_bh(&idev->lock);
+}
+
+void ipv6_mc_remap(struct inet6_dev *idev)
+{
+ ipv6_mc_up(idev);
+}
+
/* Device going down */
void ipv6_mc_down(struct inet6_dev *idev)