summaryrefslogtreecommitdiff
path: root/drivers/net/bonding
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/bonding')
-rw-r--r--drivers/net/bonding/bond_alb.c48
-rw-r--r--drivers/net/bonding/bond_main.c177
-rw-r--r--drivers/net/bonding/bond_sysfs.c14
-rw-r--r--drivers/net/bonding/bonding.h1
4 files changed, 58 insertions, 182 deletions
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index e02cc265723a..27fe329bdf83 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -1056,7 +1056,7 @@ static int alb_set_slave_mac_addr(struct slave *slave, u8 addr[])
*
*/
-static void alb_swap_mac_addr(struct bonding *bond, struct slave *slave1, struct slave *slave2)
+static void alb_swap_mac_addr(struct slave *slave1, struct slave *slave2)
{
u8 tmp_mac_addr[ETH_ALEN];
@@ -1149,7 +1149,7 @@ static void alb_change_hw_addr_on_detach(struct bonding *bond, struct slave *sla
if (found) {
/* locking: needs RTNL and nothing else */
- alb_swap_mac_addr(bond, slave, tmp_slave);
+ alb_swap_mac_addr(slave, tmp_slave);
alb_fasten_mac_swap(bond, slave, tmp_slave);
}
}
@@ -1175,16 +1175,13 @@ static void alb_change_hw_addr_on_detach(struct bonding *bond, struct slave *sla
* @slave.
*
* assumption: this function is called before @slave is attached to the
- * bond slave list.
- *
- * caller must hold the bond lock for write since the mac addresses are compared
- * and may be swapped.
+ * bond slave list.
*/
static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slave *slave)
{
- struct slave *tmp_slave1, *tmp_slave2, *free_mac_slave;
+ struct slave *tmp_slave1, *free_mac_slave = NULL;
struct slave *has_bond_addr = bond->curr_active_slave;
- int i, j, found = 0;
+ int i;
if (bond->slave_cnt == 0) {
/* this is the first slave */
@@ -1196,15 +1193,7 @@ static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slav
* slaves in the bond.
*/
if (!ether_addr_equal_64bits(slave->perm_hwaddr, bond->dev->dev_addr)) {
- bond_for_each_slave(bond, tmp_slave1, i) {
- if (ether_addr_equal_64bits(tmp_slave1->dev->dev_addr,
- slave->dev->dev_addr)) {
- found = 1;
- break;
- }
- }
-
- if (!found)
+ if (!bond_slave_has_mac(bond, slave->dev->dev_addr))
return 0;
/* Try setting slave mac to bond address and fall-through
@@ -1215,19 +1204,8 @@ static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slav
/* The slave's address is equal to the address of the bond.
* Search for a spare address in the bond for this slave.
*/
- free_mac_slave = NULL;
-
bond_for_each_slave(bond, tmp_slave1, i) {
- found = 0;
- bond_for_each_slave(bond, tmp_slave2, j) {
- if (ether_addr_equal_64bits(tmp_slave1->perm_hwaddr,
- tmp_slave2->dev->dev_addr)) {
- found = 1;
- break;
- }
- }
-
- if (!found) {
+ if (!bond_slave_has_mac(bond, tmp_slave1->perm_hwaddr)) {
/* no slave has tmp_slave1's perm addr
* as its curr addr
*/
@@ -1607,15 +1585,7 @@ int bond_alb_init_slave(struct bonding *bond, struct slave *slave)
return res;
}
- /* caller must hold the bond lock for write since the mac addresses
- * are compared and may be swapped.
- */
- read_lock(&bond->lock);
-
res = alb_handle_addr_collision_on_attach(bond, slave);
-
- read_unlock(&bond->lock);
-
if (res) {
return res;
}
@@ -1750,7 +1720,7 @@ void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave
/* curr_active_slave must be set before calling alb_swap_mac_addr */
if (swap_slave) {
/* swap mac address */
- alb_swap_mac_addr(bond, swap_slave, new_slave);
+ alb_swap_mac_addr(swap_slave, new_slave);
} else {
/* set the new_slave to the bond mac address */
alb_set_slave_mac_addr(new_slave, bond->dev->dev_addr);
@@ -1810,7 +1780,7 @@ int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr)
}
if (swap_slave) {
- alb_swap_mac_addr(bond, swap_slave, bond->curr_active_slave);
+ alb_swap_mac_addr(swap_slave, bond->curr_active_slave);
alb_fasten_mac_swap(bond, swap_slave, bond->curr_active_slave);
} else {
alb_set_slave_mac_addr(bond->curr_active_slave, bond_dev->dev_addr);
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 02d9ae7d527e..3b31c19972d4 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -706,45 +706,6 @@ static int bond_set_allmulti(struct bonding *bond, int inc)
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)
{
struct in_device *in_dev;
@@ -810,17 +771,15 @@ static void bond_resend_igmp_join_requests_delayed(struct work_struct *work)
bond_resend_igmp_join_requests(bond);
}
-/*
- * flush all members of flush->mc_list from device dev->mc_list
+/* Flush bond's hardware addresses from slave
*/
-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 bonding *bond = netdev_priv(bond_dev);
- struct netdev_hw_addr *ha;
- netdev_for_each_mc_addr(ha, bond_dev)
- dev_mc_del(slave_dev, ha->addr);
+ dev_uc_unsync(slave_dev, bond_dev);
+ dev_mc_unsync(slave_dev, bond_dev);
if (bond->params.mode == BOND_MODE_8023AD) {
/* del lacpdu mc addr from mc list */
@@ -832,22 +791,14 @@ static void bond_mc_list_flush(struct net_device *bond_dev,
/*--------------------------- Active slave change ---------------------------*/
-/*
- * Update the mc list and multicast-related flags for the new and
- * old active slaves (if any) according to the multicast mode, and
- * promiscuous flags unconditionally.
+/* Update the hardware address list and promisc/allmulti for the new and
+ * old active slaves (if any). Modes that are !USES_PRIMARY keep all
+ * slaves up date at all times; only the USES_PRIMARY modes need to call
+ * this function to swap these settings during a failover.
*/
-static void bond_mc_swap(struct bonding *bond, struct slave *new_active,
- struct slave *old_active)
+static void bond_hw_addr_swap(struct bonding *bond, struct slave *new_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 (bond->dev->flags & IFF_PROMISC)
dev_set_promiscuity(old_active->dev, -1);
@@ -855,10 +806,7 @@ static void bond_mc_swap(struct bonding *bond, struct slave *new_active,
if (bond->dev->flags & IFF_ALLMULTI)
dev_set_allmulti(old_active->dev, -1);
- netif_addr_lock_bh(bond->dev);
- netdev_for_each_mc_addr(ha, bond->dev)
- dev_mc_del(old_active->dev, ha->addr);
- netif_addr_unlock_bh(bond->dev);
+ bond_hw_addr_flush(bond->dev, old_active->dev);
}
if (new_active) {
@@ -870,8 +818,8 @@ static void bond_mc_swap(struct bonding *bond, struct slave *new_active,
dev_set_allmulti(new_active->dev, 1);
netif_addr_lock_bh(bond->dev);
- netdev_for_each_mc_addr(ha, bond->dev)
- dev_mc_add(new_active->dev, ha->addr);
+ dev_uc_sync(new_active->dev, bond->dev);
+ dev_mc_sync(new_active->dev, bond->dev);
netif_addr_unlock_bh(bond->dev);
}
}
@@ -1090,7 +1038,7 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
}
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)) {
bond_alb_handle_active_change(bond, new_active);
@@ -1533,7 +1481,6 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
struct bonding *bond = netdev_priv(bond_dev);
const struct net_device_ops *slave_ops = slave_dev->netdev_ops;
struct slave *new_slave = NULL;
- struct netdev_hw_addr *ha;
struct sockaddr addr;
int link_reporting;
int res = 0;
@@ -1713,10 +1660,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
goto err_close;
}
- /* If the mode USES_PRIMARY, then the new slave gets the
- * master's promisc (and mc) settings only if it becomes the
- * curr_active_slave, and that is taken care of later when calling
- * bond_change_active()
+ /* If the mode USES_PRIMARY, then the following is handled by
+ * bond_change_active_slave().
*/
if (!USES_PRIMARY(bond->params.mode)) {
/* set promiscuity level to new slave */
@@ -1734,9 +1679,10 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_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_add(slave_dev, ha->addr);
+
+ dev_mc_sync_multiple(slave_dev, bond_dev);
+ dev_uc_sync_multiple(slave_dev, bond_dev);
+
netif_addr_unlock_bh(bond_dev);
}
@@ -1915,11 +1861,9 @@ err_dest_symlinks:
bond_destroy_slave_symlinks(bond_dev, slave_dev);
err_detach:
- if (!USES_PRIMARY(bond->params.mode)) {
- netif_addr_lock_bh(bond_dev);
- bond_mc_list_flush(bond_dev, slave_dev);
- netif_addr_unlock_bh(bond_dev);
- }
+ if (!USES_PRIMARY(bond->params.mode))
+ bond_hw_addr_flush(bond_dev, slave_dev);
+
bond_del_vlans_from_slave(bond, slave_dev);
write_lock_bh(&bond->lock);
bond_detach_slave(bond, new_slave);
@@ -2118,9 +2062,8 @@ static int __bond_release_one(struct net_device *bond_dev,
bond_del_vlans_from_slave(bond, slave_dev);
- /* If the mode USES_PRIMARY, then we should only remove its
- * promisc and mc settings if it was the curr_active_slave, but that was
- * already taken care of above when we detached the slave
+ /* If the mode USES_PRIMARY, then this cases was handled above by
+ * bond_change_active_slave(..., NULL)
*/
if (!USES_PRIMARY(bond->params.mode)) {
/* unset promiscuity level from slave */
@@ -2131,10 +2074,7 @@ static int __bond_release_one(struct net_device *bond_dev,
if (bond_dev->flags & IFF_ALLMULTI)
dev_set_allmulti(slave_dev, -1);
- /* flush master's mc_list from slave */
- netif_addr_lock_bh(bond_dev);
- bond_mc_list_flush(bond_dev, slave_dev);
- netif_addr_unlock_bh(bond_dev);
+ bond_hw_addr_flush(bond_dev, slave_dev);
}
bond_upper_dev_unlink(bond_dev, slave_dev);
@@ -3288,7 +3228,7 @@ static int bond_slave_netdev_event(unsigned long event,
static int bond_netdev_event(struct notifier_block *this,
unsigned long event, void *ptr)
{
- struct net_device *event_dev = (struct net_device *)ptr;
+ struct net_device *event_dev = netdev_notifier_info_to_dev(ptr);
pr_debug("event_dev: %s, event: %lx\n",
event_dev ? event_dev->name : "None",
@@ -3671,19 +3611,6 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd
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)
{
struct bonding *bond = netdev_priv(bond_dev);
@@ -3697,35 +3624,29 @@ static void bond_change_rx_flags(struct net_device *bond_dev, int change)
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 netdev_hw_addr *ha;
- bool found;
+ struct slave *slave;
+ int i;
read_lock(&bond->lock);
- /* looking for addresses to add to slaves' mc list */
- netdev_for_each_mc_addr(ha, bond_dev) {
- found = bond_addr_in_mc_list(ha->addr, &bond->mc_list,
- bond_dev->addr_len);
- if (!found)
- bond_mc_add(bond, ha->addr);
- }
-
- /* looking for addresses to delete from slaves' list */
- netdev_hw_addr_list_for_each(ha, &bond->mc_list) {
- found = bond_addr_in_mc_list(ha->addr, &bond_dev->mc,
- bond_dev->addr_len);
- if (!found)
- bond_mc_del(bond, ha->addr);
+ if (USES_PRIMARY(bond->params.mode)) {
+ read_lock(&bond->curr_slave_lock);
+ slave = bond->curr_active_slave;
+ if (slave) {
+ dev_uc_sync(slave->dev, bond_dev);
+ dev_mc_sync(slave->dev, bond_dev);
+ }
+ read_unlock(&bond->curr_slave_lock);
+ } else {
+ bond_for_each_slave(bond, slave, i) {
+ dev_uc_sync_multiple(slave->dev, bond_dev);
+ dev_mc_sync_multiple(slave->dev, bond_dev);
+ }
}
- /* 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);
}
@@ -3870,11 +3791,10 @@ static int bond_set_mac_address(struct net_device *bond_dev, void *addr)
pr_debug("bond=%p, name=%s\n",
bond, bond_dev ? bond_dev->name : "None");
- /*
- * If fail_over_mac is set to active, do nothing and return
- * success. Returning an error causes ifenslave to fail.
+ /* If fail_over_mac is enabled, do nothing and return success.
+ * Returning an error causes ifenslave to fail.
*/
- if (bond->params.fail_over_mac == BOND_FOM_ACTIVE)
+ if (bond->params.fail_over_mac)
return 0;
if (!is_valid_ether_addr(sa->sa_data))
@@ -4332,7 +4252,7 @@ static const struct net_device_ops bond_netdev_ops = {
.ndo_get_stats64 = bond_get_stats,
.ndo_do_ioctl = bond_do_ioctl,
.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_set_mac_address = bond_set_mac_address,
.ndo_neigh_setup = bond_neigh_setup,
@@ -4437,8 +4357,6 @@ static void bond_uninit(struct net_device *bond_dev)
bond_debug_unregister(bond);
- __hw_addr_flush(&bond->mc_list);
-
list_for_each_entry_safe(vlan, tmp, &bond->vlan_list, vlan_list) {
list_del(&vlan->vlan_list);
kfree(vlan);
@@ -4849,7 +4767,6 @@ static int bond_init(struct net_device *bond_dev)
bond->dev_addr_from_first = true;
}
- __hw_addr_init(&bond->mc_list);
return 0;
}
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
index d7434e0a610e..f8bee4c0cbf1 100644
--- a/drivers/net/bonding/bond_sysfs.c
+++ b/drivers/net/bonding/bond_sysfs.c
@@ -231,8 +231,7 @@ static ssize_t bonding_show_slaves(struct device *d,
}
/*
- * Set the slaves in the current bond. The bond interface must be
- * up for this to succeed.
+ * Set the slaves in the current bond.
* This is supposed to be only thin wrapper for bond_enslave and bond_release.
* All hard work should be done there.
*/
@@ -363,7 +362,6 @@ static DEVICE_ATTR(mode, S_IRUGO | S_IWUSR,
/*
* Show and set the bonding transmit hash method.
- * The bond interface must be down to change the xmit hash policy.
*/
static ssize_t bonding_show_xmit_hash(struct device *d,
struct device_attribute *attr,
@@ -383,20 +381,12 @@ static ssize_t bonding_store_xmit_hash(struct device *d,
int new_value, ret = count;
struct bonding *bond = to_bond(d);
- if (bond->dev->flags & IFF_UP) {
- pr_err("%s: Interface is up. Unable to update xmit policy.\n",
- bond->dev->name);
- ret = -EPERM;
- goto out;
- }
-
new_value = bond_parse_parm(buf, xmit_hashtype_tbl);
if (new_value < 0) {
pr_err("%s: Ignoring invalid xmit hash policy value %.*s.\n",
bond->dev->name,
(int)strlen(buf) - 1, buf);
ret = -EINVAL;
- goto out;
} else {
bond->params.xmit_policy = new_value;
bond_set_mode_ops(bond, bond->params.mode);
@@ -404,7 +394,7 @@ static ssize_t bonding_store_xmit_hash(struct device *d,
bond->dev->name,
xmit_hashtype_tbl[new_value].modename, new_value);
}
-out:
+
return ret;
}
static DEVICE_ATTR(xmit_hash_policy, S_IRUGO | S_IWUSR,
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index f989e1529a29..c990b42cf7a1 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -231,7 +231,6 @@ struct bonding {
char proc_file_name[IFNAMSIZ];
#endif /* CONFIG_PROC_FS */
struct list_head bond_list;
- struct netdev_hw_addr_list mc_list;
int (*xmit_hash_policy)(struct sk_buff *, int);
u16 rr_tx_counter;
struct ad_bond_info ad_info;