Commit 303d1cbf authored by Jay Vosburgh's avatar Jay Vosburgh Committed by David S. Miller

bonding: Convert hw addr handling to sync/unsync, support ucast addresses

This patch converts bonding to use the dev_uc/mc_sync and
dev_uc/mc_sync_multiple functions for updating the hardware addresses
of bonding slaves.

	The existing functions to add or remove addresses are removed,
and their functionality is replaced with calls to dev_mc_sync or
dev_mc_sync_multiple, depending upon the bonding mode.

	Calls to dev_uc_sync and dev_uc_sync_multiple are also added,
so that unicast addresses added to a bond will be properly synced with
its slaves.

	Various functions are renamed to better reflect the new
situation, and relevant comments are updated.
Signed-off-by: default avatarJay Vosburgh <fubar@us.ibm.com>
Cc: Vlad Yasevich <vyasevic@redhat.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent ca162a82
...@@ -706,45 +706,6 @@ static int bond_set_allmulti(struct bonding *bond, int inc) ...@@ -706,45 +706,6 @@ static int bond_set_allmulti(struct bonding *bond, int inc)
return err; return err;
} }
/*
* Add a Multicast address to slaves
* according to mode
*/
static void bond_mc_add(struct bonding *bond, void *addr)
{
if (USES_PRIMARY(bond->params.mode)) {
/* write lock already acquired */
if (bond->curr_active_slave)
dev_mc_add(bond->curr_active_slave->dev, addr);
} else {
struct slave *slave;
int i;
bond_for_each_slave(bond, slave, i)
dev_mc_add(slave->dev, addr);
}
}
/*
* Remove a multicast address from slave
* according to mode
*/
static void bond_mc_del(struct bonding *bond, void *addr)
{
if (USES_PRIMARY(bond->params.mode)) {
/* write lock already acquired */
if (bond->curr_active_slave)
dev_mc_del(bond->curr_active_slave->dev, addr);
} else {
struct slave *slave;
int i;
bond_for_each_slave(bond, slave, i) {
dev_mc_del(slave->dev, addr);
}
}
}
static void __bond_resend_igmp_join_requests(struct net_device *dev) static void __bond_resend_igmp_join_requests(struct net_device *dev)
{ {
struct in_device *in_dev; struct in_device *in_dev;
...@@ -803,17 +764,15 @@ static void bond_resend_igmp_join_requests_delayed(struct work_struct *work) ...@@ -803,17 +764,15 @@ static void bond_resend_igmp_join_requests_delayed(struct work_struct *work)
bond_resend_igmp_join_requests(bond); bond_resend_igmp_join_requests(bond);
} }
/* /* Flush bond's hardware addresses from slave
* flush all members of flush->mc_list from device dev->mc_list
*/ */
static void bond_mc_list_flush(struct net_device *bond_dev, static void bond_hw_addr_flush(struct net_device *bond_dev,
struct net_device *slave_dev) struct net_device *slave_dev)
{ {
struct bonding *bond = netdev_priv(bond_dev); struct bonding *bond = netdev_priv(bond_dev);
struct netdev_hw_addr *ha;
netdev_for_each_mc_addr(ha, bond_dev) dev_uc_unsync(slave_dev, bond_dev);
dev_mc_del(slave_dev, ha->addr); dev_mc_unsync(slave_dev, bond_dev);
if (bond->params.mode == BOND_MODE_8023AD) { if (bond->params.mode == BOND_MODE_8023AD) {
/* del lacpdu mc addr from mc list */ /* del lacpdu mc addr from mc list */
...@@ -825,22 +784,14 @@ static void bond_mc_list_flush(struct net_device *bond_dev, ...@@ -825,22 +784,14 @@ static void bond_mc_list_flush(struct net_device *bond_dev,
/*--------------------------- Active slave change ---------------------------*/ /*--------------------------- Active slave change ---------------------------*/
/* /* Update the hardware address list and promisc/allmulti for the new and
* Update the mc list and multicast-related flags for the new and * old active slaves (if any). Modes that are !USES_PRIMARY keep all
* old active slaves (if any) according to the multicast mode, and * slaves up date at all times; only the USES_PRIMARY modes need to call
* promiscuous flags unconditionally. * this function to swap these settings during a failover.
*/ */
static void bond_mc_swap(struct bonding *bond, struct slave *new_active, static void bond_hw_addr_swap(struct bonding *bond, struct slave *new_active,
struct slave *old_active) struct slave *old_active)
{ {
struct netdev_hw_addr *ha;
if (!USES_PRIMARY(bond->params.mode))
/* nothing to do - mc list is already up-to-date on
* all slaves
*/
return;
if (old_active) { if (old_active) {
if (bond->dev->flags & IFF_PROMISC) if (bond->dev->flags & IFF_PROMISC)
dev_set_promiscuity(old_active->dev, -1); dev_set_promiscuity(old_active->dev, -1);
...@@ -848,10 +799,7 @@ static void bond_mc_swap(struct bonding *bond, struct slave *new_active, ...@@ -848,10 +799,7 @@ static void bond_mc_swap(struct bonding *bond, struct slave *new_active,
if (bond->dev->flags & IFF_ALLMULTI) if (bond->dev->flags & IFF_ALLMULTI)
dev_set_allmulti(old_active->dev, -1); dev_set_allmulti(old_active->dev, -1);
netif_addr_lock_bh(bond->dev); bond_hw_addr_flush(bond->dev, old_active->dev);
netdev_for_each_mc_addr(ha, bond->dev)
dev_mc_del(old_active->dev, ha->addr);
netif_addr_unlock_bh(bond->dev);
} }
if (new_active) { if (new_active) {
...@@ -863,8 +811,8 @@ static void bond_mc_swap(struct bonding *bond, struct slave *new_active, ...@@ -863,8 +811,8 @@ static void bond_mc_swap(struct bonding *bond, struct slave *new_active,
dev_set_allmulti(new_active->dev, 1); dev_set_allmulti(new_active->dev, 1);
netif_addr_lock_bh(bond->dev); netif_addr_lock_bh(bond->dev);
netdev_for_each_mc_addr(ha, bond->dev) dev_uc_sync(new_active->dev, bond->dev);
dev_mc_add(new_active->dev, ha->addr); dev_mc_sync(new_active->dev, bond->dev);
netif_addr_unlock_bh(bond->dev); netif_addr_unlock_bh(bond->dev);
} }
} }
...@@ -1083,7 +1031,7 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active) ...@@ -1083,7 +1031,7 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
} }
if (USES_PRIMARY(bond->params.mode)) if (USES_PRIMARY(bond->params.mode))
bond_mc_swap(bond, new_active, old_active); bond_hw_addr_swap(bond, new_active, old_active);
if (bond_is_lb(bond)) { if (bond_is_lb(bond)) {
bond_alb_handle_active_change(bond, new_active); bond_alb_handle_active_change(bond, new_active);
...@@ -1526,7 +1474,6 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) ...@@ -1526,7 +1474,6 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
struct bonding *bond = netdev_priv(bond_dev); struct bonding *bond = netdev_priv(bond_dev);
const struct net_device_ops *slave_ops = slave_dev->netdev_ops; const struct net_device_ops *slave_ops = slave_dev->netdev_ops;
struct slave *new_slave = NULL; struct slave *new_slave = NULL;
struct netdev_hw_addr *ha;
struct sockaddr addr; struct sockaddr addr;
int link_reporting; int link_reporting;
int res = 0; int res = 0;
...@@ -1706,10 +1653,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) ...@@ -1706,10 +1653,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
goto err_close; goto err_close;
} }
/* If the mode USES_PRIMARY, then the new slave gets the /* If the mode USES_PRIMARY, then the following is handled by
* master's promisc (and mc) settings only if it becomes the * bond_change_active_slave().
* curr_active_slave, and that is taken care of later when calling
* bond_change_active()
*/ */
if (!USES_PRIMARY(bond->params.mode)) { if (!USES_PRIMARY(bond->params.mode)) {
/* set promiscuity level to new slave */ /* set promiscuity level to new slave */
...@@ -1727,9 +1672,10 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) ...@@ -1727,9 +1672,10 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
} }
netif_addr_lock_bh(bond_dev); netif_addr_lock_bh(bond_dev);
/* upload master's mc_list to new slave */
netdev_for_each_mc_addr(ha, bond_dev) dev_mc_sync_multiple(slave_dev, bond_dev);
dev_mc_add(slave_dev, ha->addr); dev_uc_sync_multiple(slave_dev, bond_dev);
netif_addr_unlock_bh(bond_dev); netif_addr_unlock_bh(bond_dev);
} }
...@@ -1908,11 +1854,9 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) ...@@ -1908,11 +1854,9 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
bond_destroy_slave_symlinks(bond_dev, slave_dev); bond_destroy_slave_symlinks(bond_dev, slave_dev);
err_detach: err_detach:
if (!USES_PRIMARY(bond->params.mode)) { if (!USES_PRIMARY(bond->params.mode))
netif_addr_lock_bh(bond_dev); bond_hw_addr_flush(bond_dev, slave_dev);
bond_mc_list_flush(bond_dev, slave_dev);
netif_addr_unlock_bh(bond_dev);
}
bond_del_vlans_from_slave(bond, slave_dev); bond_del_vlans_from_slave(bond, slave_dev);
write_lock_bh(&bond->lock); write_lock_bh(&bond->lock);
bond_detach_slave(bond, new_slave); bond_detach_slave(bond, new_slave);
...@@ -2107,9 +2051,8 @@ static int __bond_release_one(struct net_device *bond_dev, ...@@ -2107,9 +2051,8 @@ static int __bond_release_one(struct net_device *bond_dev,
bond_del_vlans_from_slave(bond, slave_dev); bond_del_vlans_from_slave(bond, slave_dev);
/* If the mode USES_PRIMARY, then we should only remove its /* If the mode USES_PRIMARY, then this cases was handled above by
* promisc and mc settings if it was the curr_active_slave, but that was * bond_change_active_slave(..., NULL)
* already taken care of above when we detached the slave
*/ */
if (!USES_PRIMARY(bond->params.mode)) { if (!USES_PRIMARY(bond->params.mode)) {
/* unset promiscuity level from slave */ /* unset promiscuity level from slave */
...@@ -2120,10 +2063,7 @@ static int __bond_release_one(struct net_device *bond_dev, ...@@ -2120,10 +2063,7 @@ static int __bond_release_one(struct net_device *bond_dev,
if (bond_dev->flags & IFF_ALLMULTI) if (bond_dev->flags & IFF_ALLMULTI)
dev_set_allmulti(slave_dev, -1); dev_set_allmulti(slave_dev, -1);
/* flush master's mc_list from slave */ bond_hw_addr_flush(bond_dev, slave_dev);
netif_addr_lock_bh(bond_dev);
bond_mc_list_flush(bond_dev, slave_dev);
netif_addr_unlock_bh(bond_dev);
} }
bond_upper_dev_unlink(bond_dev, slave_dev); bond_upper_dev_unlink(bond_dev, slave_dev);
...@@ -3660,19 +3600,6 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd ...@@ -3660,19 +3600,6 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd
return res; return res;
} }
static bool bond_addr_in_mc_list(unsigned char *addr,
struct netdev_hw_addr_list *list,
int addrlen)
{
struct netdev_hw_addr *ha;
netdev_hw_addr_list_for_each(ha, list)
if (!memcmp(ha->addr, addr, addrlen))
return true;
return false;
}
static void bond_change_rx_flags(struct net_device *bond_dev, int change) static void bond_change_rx_flags(struct net_device *bond_dev, int change)
{ {
struct bonding *bond = netdev_priv(bond_dev); struct bonding *bond = netdev_priv(bond_dev);
...@@ -3686,35 +3613,29 @@ static void bond_change_rx_flags(struct net_device *bond_dev, int change) ...@@ -3686,35 +3613,29 @@ static void bond_change_rx_flags(struct net_device *bond_dev, int change)
bond_dev->flags & IFF_ALLMULTI ? 1 : -1); bond_dev->flags & IFF_ALLMULTI ? 1 : -1);
} }
static void bond_set_multicast_list(struct net_device *bond_dev) static void bond_set_rx_mode(struct net_device *bond_dev)
{ {
struct bonding *bond = netdev_priv(bond_dev); struct bonding *bond = netdev_priv(bond_dev);
struct netdev_hw_addr *ha; struct slave *slave;
bool found; int i;
read_lock(&bond->lock); read_lock(&bond->lock);
/* looking for addresses to add to slaves' mc list */ if (USES_PRIMARY(bond->params.mode)) {
netdev_for_each_mc_addr(ha, bond_dev) { read_lock(&bond->curr_slave_lock);
found = bond_addr_in_mc_list(ha->addr, &bond->mc_list, slave = bond->curr_active_slave;
bond_dev->addr_len); if (slave) {
if (!found) dev_uc_sync(slave->dev, bond_dev);
bond_mc_add(bond, ha->addr); dev_mc_sync(slave->dev, bond_dev);
} }
read_unlock(&bond->curr_slave_lock);
/* looking for addresses to delete from slaves' list */ } else {
netdev_hw_addr_list_for_each(ha, &bond->mc_list) { bond_for_each_slave(bond, slave, i) {
found = bond_addr_in_mc_list(ha->addr, &bond_dev->mc, dev_uc_sync_multiple(slave->dev, bond_dev);
bond_dev->addr_len); dev_mc_sync_multiple(slave->dev, bond_dev);
if (!found) }
bond_mc_del(bond, ha->addr);
} }
/* save master's multicast list */
__hw_addr_flush(&bond->mc_list);
__hw_addr_add_multiple(&bond->mc_list, &bond_dev->mc,
bond_dev->addr_len, NETDEV_HW_ADDR_T_MULTICAST);
read_unlock(&bond->lock); read_unlock(&bond->lock);
} }
...@@ -4321,7 +4242,7 @@ static const struct net_device_ops bond_netdev_ops = { ...@@ -4321,7 +4242,7 @@ static const struct net_device_ops bond_netdev_ops = {
.ndo_get_stats64 = bond_get_stats, .ndo_get_stats64 = bond_get_stats,
.ndo_do_ioctl = bond_do_ioctl, .ndo_do_ioctl = bond_do_ioctl,
.ndo_change_rx_flags = bond_change_rx_flags, .ndo_change_rx_flags = bond_change_rx_flags,
.ndo_set_rx_mode = bond_set_multicast_list, .ndo_set_rx_mode = bond_set_rx_mode,
.ndo_change_mtu = bond_change_mtu, .ndo_change_mtu = bond_change_mtu,
.ndo_set_mac_address = bond_set_mac_address, .ndo_set_mac_address = bond_set_mac_address,
.ndo_neigh_setup = bond_neigh_setup, .ndo_neigh_setup = bond_neigh_setup,
...@@ -4426,8 +4347,6 @@ static void bond_uninit(struct net_device *bond_dev) ...@@ -4426,8 +4347,6 @@ static void bond_uninit(struct net_device *bond_dev)
bond_debug_unregister(bond); bond_debug_unregister(bond);
__hw_addr_flush(&bond->mc_list);
list_for_each_entry_safe(vlan, tmp, &bond->vlan_list, vlan_list) { list_for_each_entry_safe(vlan, tmp, &bond->vlan_list, vlan_list) {
list_del(&vlan->vlan_list); list_del(&vlan->vlan_list);
kfree(vlan); kfree(vlan);
...@@ -4838,7 +4757,6 @@ static int bond_init(struct net_device *bond_dev) ...@@ -4838,7 +4757,6 @@ static int bond_init(struct net_device *bond_dev)
bond->dev_addr_from_first = true; bond->dev_addr_from_first = true;
} }
__hw_addr_init(&bond->mc_list);
return 0; return 0;
} }
......
...@@ -231,7 +231,6 @@ struct bonding { ...@@ -231,7 +231,6 @@ struct bonding {
char proc_file_name[IFNAMSIZ]; char proc_file_name[IFNAMSIZ];
#endif /* CONFIG_PROC_FS */ #endif /* CONFIG_PROC_FS */
struct list_head bond_list; struct list_head bond_list;
struct netdev_hw_addr_list mc_list;
int (*xmit_hash_policy)(struct sk_buff *, int); int (*xmit_hash_policy)(struct sk_buff *, int);
u16 rr_tx_counter; u16 rr_tx_counter;
struct ad_bond_info ad_info; struct ad_bond_info ad_info;
......
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