diff options
-rw-r--r-- | drivers/net/bonding/bond_main.c | 9 | ||||
-rw-r--r-- | include/linux/igmp.h | 2 | ||||
-rw-r--r-- | include/linux/netdevice.h | 3 | ||||
-rw-r--r-- | include/linux/notifier.h | 2 | ||||
-rw-r--r-- | include/net/addrconf.h | 2 | ||||
-rw-r--r-- | net/core/dev.c | 4 | ||||
-rw-r--r-- | net/ipv4/devinet.c | 6 | ||||
-rw-r--r-- | net/ipv4/igmp.c | 22 | ||||
-rw-r--r-- | net/ipv6/addrconf.c | 19 | ||||
-rw-r--r-- | net/ipv6/mcast.c | 19 |
10 files changed, 82 insertions, 6 deletions
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index a7e731f8a0da..6419cf9a4fa6 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 92fbd8cbd68f..fe158e0e20e6 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 65ee1929b2b1..f46db6c7a734 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 81bc252dc8ac..44428d247dbe 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 7b55ab215a64..0f7c37825fc1 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 84945470ab38..560c8c9c03ab 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 3863c3a4223f..07336c6201f0 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 01b4284ed694..d41e5de79a82 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 c9b369034a40..f216a41ceb22 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 71c3dacec1ed..f9fcf690bd5d 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) |