Skip to content

Commit 75c7850

Browse files
Moni Shouadavem330
authored andcommitted
bonding: remap muticast addresses without using dev_close() and dev_open()
This patch fixes commit e36b9d1. The approach there is to call dev_close()/dev_open() whenever the device type is changed in order to remap the device IP multicast addresses to HW multicast addresses. This approach suffers from 2 drawbacks: *. It assumes tha the device is UP when calling dev_close(), or otherwise dev_close() has no affect. It is worth to mention that initscripts (Redhat) and sysconfig (Suse) doesn't act the same in this matter. *. dev_close() has other side affects, like deleting entries from the routing table, which might be unnecessary. The fix here is to directly remap the IP multicast addresses to HW multicast addresses for a bonding device that changes its type, and nothing else. Reported-by: Jason Gunthorpe <jgunthorpe@obsidianresearch.com> Signed-off-by: Moni Shoua <monis@voltaire.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 481a819 commit 75c7850

File tree

10 files changed

+82
-6
lines changed

10 files changed

+82
-6
lines changed

drivers/net/bonding/bond_main.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1211,7 +1211,7 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
12111211
write_unlock_bh(&bond->curr_slave_lock);
12121212
read_unlock(&bond->lock);
12131213

1214-
netdev_bonding_change(bond->dev);
1214+
netdev_bonding_change(bond->dev, NETDEV_BONDING_FAILOVER);
12151215

12161216
read_lock(&bond->lock);
12171217
write_lock_bh(&bond->curr_slave_lock);
@@ -1469,14 +1469,17 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
14691469
*/
14701470
if (bond->slave_cnt == 0) {
14711471
if (bond_dev->type != slave_dev->type) {
1472-
dev_close(bond_dev);
14731472
pr_debug("%s: change device type from %d to %d\n",
14741473
bond_dev->name, bond_dev->type, slave_dev->type);
1474+
1475+
netdev_bonding_change(bond_dev, NETDEV_BONDING_OLDTYPE);
1476+
14751477
if (slave_dev->type != ARPHRD_ETHER)
14761478
bond_setup_by_slave(bond_dev, slave_dev);
14771479
else
14781480
ether_setup(bond_dev);
1479-
dev_open(bond_dev);
1481+
1482+
netdev_bonding_change(bond_dev, NETDEV_BONDING_NEWTYPE);
14801483
}
14811484
} else if (bond_dev->type != slave_dev->type) {
14821485
pr_err(DRV_NAME ": %s ether type (%d) is different "

include/linux/igmp.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,8 @@ extern void ip_mc_init_dev(struct in_device *);
233233
extern void ip_mc_destroy_dev(struct in_device *);
234234
extern void ip_mc_up(struct in_device *);
235235
extern void ip_mc_down(struct in_device *);
236+
extern void ip_mc_unmap(struct in_device *);
237+
extern void ip_mc_remap(struct in_device *);
236238
extern void ip_mc_dec_group(struct in_device *in_dev, __be32 addr);
237239
extern void ip_mc_inc_group(struct in_device *in_dev, __be32 addr);
238240
extern void ip_mc_rejoin_group(struct ip_mc_list *im);

include/linux/netdevice.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1873,7 +1873,8 @@ extern void __dev_addr_unsync(struct dev_addr_list **to, int *to_count, struct
18731873
extern int dev_set_promiscuity(struct net_device *dev, int inc);
18741874
extern int dev_set_allmulti(struct net_device *dev, int inc);
18751875
extern void netdev_state_change(struct net_device *dev);
1876-
extern void netdev_bonding_change(struct net_device *dev);
1876+
extern void netdev_bonding_change(struct net_device *dev,
1877+
unsigned long event);
18771878
extern void netdev_features_change(struct net_device *dev);
18781879
/* Load a device via the kmod */
18791880
extern void dev_load(struct net *net, const char *name);

include/linux/notifier.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,8 @@ static inline int notifier_to_errno(int ret)
199199
#define NETDEV_FEAT_CHANGE 0x000B
200200
#define NETDEV_BONDING_FAILOVER 0x000C
201201
#define NETDEV_PRE_UP 0x000D
202+
#define NETDEV_BONDING_OLDTYPE 0x000E
203+
#define NETDEV_BONDING_NEWTYPE 0x000F
202204

203205
#define SYS_DOWN 0x0001 /* Notify of system down */
204206
#define SYS_RESTART SYS_DOWN

include/net/addrconf.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,8 @@ extern int __ipv6_dev_mc_dec(struct inet6_dev *idev, const struct in6_addr *addr
143143
extern int ipv6_dev_mc_dec(struct net_device *dev, const struct in6_addr *addr);
144144
extern void ipv6_mc_up(struct inet6_dev *idev);
145145
extern void ipv6_mc_down(struct inet6_dev *idev);
146+
extern void ipv6_mc_unmap(struct inet6_dev *idev);
147+
extern void ipv6_mc_remap(struct inet6_dev *idev);
146148
extern void ipv6_mc_init_dev(struct inet6_dev *idev);
147149
extern void ipv6_mc_destroy_dev(struct inet6_dev *idev);
148150
extern void addrconf_dad_failure(struct inet6_ifaddr *ifp);

net/core/dev.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1017,9 +1017,9 @@ void netdev_state_change(struct net_device *dev)
10171017
}
10181018
EXPORT_SYMBOL(netdev_state_change);
10191019

1020-
void netdev_bonding_change(struct net_device *dev)
1020+
void netdev_bonding_change(struct net_device *dev, unsigned long event)
10211021
{
1022-
call_netdevice_notifiers(NETDEV_BONDING_FAILOVER, dev);
1022+
call_netdevice_notifiers(event, dev);
10231023
}
10241024
EXPORT_SYMBOL(netdev_bonding_change);
10251025

net/ipv4/devinet.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1087,6 +1087,12 @@ static int inetdev_event(struct notifier_block *this, unsigned long event,
10871087
case NETDEV_DOWN:
10881088
ip_mc_down(in_dev);
10891089
break;
1090+
case NETDEV_BONDING_OLDTYPE:
1091+
ip_mc_unmap(in_dev);
1092+
break;
1093+
case NETDEV_BONDING_NEWTYPE:
1094+
ip_mc_remap(in_dev);
1095+
break;
10901096
case NETDEV_CHANGEMTU:
10911097
if (inetdev_valid_mtu(dev->mtu))
10921098
break;

net/ipv4/igmp.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1298,6 +1298,28 @@ void ip_mc_dec_group(struct in_device *in_dev, __be32 addr)
12981298
}
12991299
}
13001300

1301+
/* Device changing type */
1302+
1303+
void ip_mc_unmap(struct in_device *in_dev)
1304+
{
1305+
struct ip_mc_list *i;
1306+
1307+
ASSERT_RTNL();
1308+
1309+
for (i = in_dev->mc_list; i; i = i->next)
1310+
igmp_group_dropped(i);
1311+
}
1312+
1313+
void ip_mc_remap(struct in_device *in_dev)
1314+
{
1315+
struct ip_mc_list *i;
1316+
1317+
ASSERT_RTNL();
1318+
1319+
for (i = in_dev->mc_list; i; i = i->next)
1320+
igmp_group_added(i);
1321+
}
1322+
13011323
/* Device going down */
13021324

13031325
void ip_mc_down(struct in_device *in_dev)

net/ipv6/addrconf.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,8 @@ static DEFINE_SPINLOCK(addrconf_verify_lock);
137137
static void addrconf_join_anycast(struct inet6_ifaddr *ifp);
138138
static void addrconf_leave_anycast(struct inet6_ifaddr *ifp);
139139

140+
static void addrconf_bonding_change(struct net_device *dev,
141+
unsigned long event);
140142
static int addrconf_ifdown(struct net_device *dev, int how);
141143

142144
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,
25822584
return notifier_from_errno(err);
25832585
}
25842586
break;
2587+
case NETDEV_BONDING_OLDTYPE:
2588+
case NETDEV_BONDING_NEWTYPE:
2589+
addrconf_bonding_change(dev, event);
2590+
break;
25852591
}
25862592

25872593
return NOTIFY_OK;
@@ -2595,6 +2601,19 @@ static struct notifier_block ipv6_dev_notf = {
25952601
.priority = 0
25962602
};
25972603

2604+
static void addrconf_bonding_change(struct net_device *dev, unsigned long event)
2605+
{
2606+
struct inet6_dev *idev;
2607+
ASSERT_RTNL();
2608+
2609+
idev = __in6_dev_get(dev);
2610+
2611+
if (event == NETDEV_BONDING_NEWTYPE)
2612+
ipv6_mc_remap(idev);
2613+
else if (event == NETDEV_BONDING_OLDTYPE)
2614+
ipv6_mc_unmap(idev);
2615+
}
2616+
25982617
static int addrconf_ifdown(struct net_device *dev, int how)
25992618
{
26002619
struct inet6_dev *idev;

net/ipv6/mcast.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2249,6 +2249,25 @@ static void igmp6_timer_handler(unsigned long data)
22492249
ma_put(ma);
22502250
}
22512251

2252+
/* Device changing type */
2253+
2254+
void ipv6_mc_unmap(struct inet6_dev *idev)
2255+
{
2256+
struct ifmcaddr6 *i;
2257+
2258+
/* Install multicast list, except for all-nodes (already installed) */
2259+
2260+
read_lock_bh(&idev->lock);
2261+
for (i = idev->mc_list; i; i = i->next)
2262+
igmp6_group_dropped(i);
2263+
read_unlock_bh(&idev->lock);
2264+
}
2265+
2266+
void ipv6_mc_remap(struct inet6_dev *idev)
2267+
{
2268+
ipv6_mc_up(idev);
2269+
}
2270+
22522271
/* Device going down */
22532272

22542273
void ipv6_mc_down(struct inet6_dev *idev)

0 commit comments

Comments
 (0)