]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/net/bonding/bond_main.c
bonding: Fix broken promiscuity reference counting issue
[karo-tx-linux.git] / drivers / net / bonding / bond_main.c
index e48cb339c0c6e5b71eb4ec24bef6d4f8238ea665..e883bfe2e727aa1bf6fd2fb2cea2375578c8c06d 100644 (file)
@@ -77,6 +77,7 @@
 #include <net/net_namespace.h>
 #include <net/netns/generic.h>
 #include <net/pkt_sched.h>
+#include <linux/rculist.h>
 #include "bonding.h"
 #include "bond_3ad.h"
 #include "bond_alb.h"
@@ -106,7 +107,7 @@ static char *arp_ip_target[BOND_MAX_ARP_TARGETS];
 static char *arp_validate;
 static char *arp_all_targets;
 static char *fail_over_mac;
-static int all_slaves_active = 0;
+static int all_slaves_active;
 static struct bond_params bonding_defaults;
 static int resend_igmp = BOND_DEFAULT_RESEND_IGMP;
 
@@ -273,7 +274,7 @@ const char *bond_mode_name(int mode)
                [BOND_MODE_ALB] = "adaptive load balancing",
        };
 
-       if (mode < 0 || mode > BOND_MODE_ALB)
+       if (mode < BOND_MODE_ROUNDROBIN || mode > BOND_MODE_ALB)
                return "unknown";
 
        return names[mode];
@@ -281,116 +282,6 @@ const char *bond_mode_name(int mode)
 
 /*---------------------------------- VLAN -----------------------------------*/
 
-/**
- * bond_add_vlan - add a new vlan id on bond
- * @bond: bond that got the notification
- * @vlan_id: the vlan id to add
- *
- * Returns -ENOMEM if allocation failed.
- */
-static int bond_add_vlan(struct bonding *bond, unsigned short vlan_id)
-{
-       struct vlan_entry *vlan;
-
-       pr_debug("bond: %s, vlan id %d\n",
-                (bond ? bond->dev->name : "None"), vlan_id);
-
-       vlan = kzalloc(sizeof(struct vlan_entry), GFP_KERNEL);
-       if (!vlan)
-               return -ENOMEM;
-
-       INIT_LIST_HEAD(&vlan->vlan_list);
-       vlan->vlan_id = vlan_id;
-
-       write_lock_bh(&bond->lock);
-
-       list_add_tail(&vlan->vlan_list, &bond->vlan_list);
-
-       write_unlock_bh(&bond->lock);
-
-       pr_debug("added VLAN ID %d on bond %s\n", vlan_id, bond->dev->name);
-
-       return 0;
-}
-
-/**
- * bond_del_vlan - delete a vlan id from bond
- * @bond: bond that got the notification
- * @vlan_id: the vlan id to delete
- *
- * returns -ENODEV if @vlan_id was not found in @bond.
- */
-static int bond_del_vlan(struct bonding *bond, unsigned short vlan_id)
-{
-       struct vlan_entry *vlan;
-       int res = -ENODEV;
-
-       pr_debug("bond: %s, vlan id %d\n", bond->dev->name, vlan_id);
-
-       block_netpoll_tx();
-       write_lock_bh(&bond->lock);
-
-       list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
-               if (vlan->vlan_id == vlan_id) {
-                       list_del(&vlan->vlan_list);
-
-                       if (bond_is_lb(bond))
-                               bond_alb_clear_vlan(bond, vlan_id);
-
-                       pr_debug("removed VLAN ID %d from bond %s\n",
-                                vlan_id, bond->dev->name);
-
-                       kfree(vlan);
-
-                       res = 0;
-                       goto out;
-               }
-       }
-
-       pr_debug("couldn't find VLAN ID %d in bond %s\n",
-                vlan_id, bond->dev->name);
-
-out:
-       write_unlock_bh(&bond->lock);
-       unblock_netpoll_tx();
-       return res;
-}
-
-/**
- * bond_next_vlan - safely skip to the next item in the vlans list.
- * @bond: the bond we're working on
- * @curr: item we're advancing from
- *
- * Returns %NULL if list is empty, bond->next_vlan if @curr is %NULL,
- * or @curr->next otherwise (even if it is @curr itself again).
- *
- * Caller must hold bond->lock
- */
-struct vlan_entry *bond_next_vlan(struct bonding *bond, struct vlan_entry *curr)
-{
-       struct vlan_entry *next, *last;
-
-       if (list_empty(&bond->vlan_list))
-               return NULL;
-
-       if (!curr) {
-               next = list_entry(bond->vlan_list.next,
-                                 struct vlan_entry, vlan_list);
-       } else {
-               last = list_entry(bond->vlan_list.prev,
-                                 struct vlan_entry, vlan_list);
-               if (last == curr) {
-                       next = list_entry(bond->vlan_list.next,
-                                         struct vlan_entry, vlan_list);
-               } else {
-                       next = list_entry(curr->vlan_list.next,
-                                         struct vlan_entry, vlan_list);
-               }
-       }
-
-       return next;
-}
-
 /**
  * bond_dev_queue_xmit - Prepare skb for xmit.
  *
@@ -441,28 +332,20 @@ static int bond_vlan_rx_add_vid(struct net_device *bond_dev,
                                __be16 proto, u16 vid)
 {
        struct bonding *bond = netdev_priv(bond_dev);
-       struct slave *slave, *stop_at;
-       int i, res;
+       struct slave *slave;
+       int res;
 
-       bond_for_each_slave(bond, slave, i) {
+       bond_for_each_slave(bond, slave) {
                res = vlan_vid_add(slave->dev, proto, vid);
                if (res)
                        goto unwind;
        }
 
-       res = bond_add_vlan(bond, vid);
-       if (res) {
-               pr_err("%s: Error: Failed to add vlan id %d\n",
-                      bond_dev->name, vid);
-               return res;
-       }
-
        return 0;
 
 unwind:
-       /* unwind from head to the slave that failed */
-       stop_at = slave;
-       bond_for_each_slave_from_to(bond, slave, i, bond->first_slave, stop_at)
+       /* unwind from the slave that failed */
+       bond_for_each_slave_continue_reverse(bond, slave)
                vlan_vid_del(slave->dev, proto, vid);
 
        return res;
@@ -478,48 +361,16 @@ static int bond_vlan_rx_kill_vid(struct net_device *bond_dev,
 {
        struct bonding *bond = netdev_priv(bond_dev);
        struct slave *slave;
-       int i, res;
 
-       bond_for_each_slave(bond, slave, i)
+       bond_for_each_slave(bond, slave)
                vlan_vid_del(slave->dev, proto, vid);
 
-       res = bond_del_vlan(bond, vid);
-       if (res) {
-               pr_err("%s: Error: Failed to remove vlan id %d\n",
-                      bond_dev->name, vid);
-               return res;
-       }
+       if (bond_is_lb(bond))
+               bond_alb_clear_vlan(bond, vid);
 
        return 0;
 }
 
-static void bond_add_vlans_on_slave(struct bonding *bond, struct net_device *slave_dev)
-{
-       struct vlan_entry *vlan;
-       int res;
-
-       list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
-               res = vlan_vid_add(slave_dev, htons(ETH_P_8021Q),
-                                  vlan->vlan_id);
-               if (res)
-                       pr_warning("%s: Failed to add vlan id %d to device %s\n",
-                                  bond->dev->name, vlan->vlan_id,
-                                  slave_dev->name);
-       }
-}
-
-static void bond_del_vlans_from_slave(struct bonding *bond,
-                                     struct net_device *slave_dev)
-{
-       struct vlan_entry *vlan;
-
-       list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
-               if (!vlan->vlan_id)
-                       continue;
-               vlan_vid_del(slave_dev, htons(ETH_P_8021Q), vlan->vlan_id);
-       }
-}
-
 /*------------------------------- Link status -------------------------------*/
 
 /*
@@ -532,15 +383,14 @@ static void bond_del_vlans_from_slave(struct bonding *bond,
 static int bond_set_carrier(struct bonding *bond)
 {
        struct slave *slave;
-       int i;
 
-       if (bond->slave_cnt == 0)
+       if (list_empty(&bond->slave_list))
                goto down;
 
        if (bond->params.mode == BOND_MODE_8023AD)
                return bond_3ad_set_carrier(bond);
 
-       bond_for_each_slave(bond, slave, i) {
+       bond_for_each_slave(bond, slave) {
                if (slave->link == BOND_LINK_UP) {
                        if (!netif_carrier_ok(bond->dev)) {
                                netif_carrier_on(bond->dev);
@@ -681,8 +531,8 @@ static int bond_set_promiscuity(struct bonding *bond, int inc)
                }
        } else {
                struct slave *slave;
-               int i;
-               bond_for_each_slave(bond, slave, i) {
+
+               bond_for_each_slave(bond, slave) {
                        err = dev_set_promiscuity(slave->dev, inc);
                        if (err)
                                return err;
@@ -705,8 +555,8 @@ static int bond_set_allmulti(struct bonding *bond, int inc)
                }
        } else {
                struct slave *slave;
-               int i;
-               bond_for_each_slave(bond, slave, i) {
+
+               bond_for_each_slave(bond, slave) {
                        err = dev_set_allmulti(slave->dev, inc);
                        if (err)
                                return err;
@@ -715,15 +565,6 @@ static int bond_set_allmulti(struct bonding *bond, int inc)
        return err;
 }
 
-static void __bond_resend_igmp_join_requests(struct net_device *dev)
-{
-       struct in_device *in_dev;
-
-       in_dev = __in_dev_get_rcu(dev);
-       if (in_dev)
-               ip_mc_rejoin_groups(in_dev);
-}
-
 /*
  * Retrieve the list of registered multicast addresses for the bonding
  * device and retransmit an IGMP JOIN request to the current active
@@ -731,33 +572,12 @@ static void __bond_resend_igmp_join_requests(struct net_device *dev)
  */
 static void bond_resend_igmp_join_requests(struct bonding *bond)
 {
-       struct net_device *bond_dev, *vlan_dev, *upper_dev;
-       struct vlan_entry *vlan;
-
-       read_lock(&bond->lock);
-       rcu_read_lock();
-
-       bond_dev = bond->dev;
-
-       /* rejoin all groups on bond device */
-       __bond_resend_igmp_join_requests(bond_dev);
-
-       /*
-        * if bond is enslaved to a bridge,
-        * then rejoin all groups on its master
-        */
-       upper_dev = netdev_master_upper_dev_get_rcu(bond_dev);
-       if (upper_dev && upper_dev->priv_flags & IFF_EBRIDGE)
-               __bond_resend_igmp_join_requests(upper_dev);
-
-       /* rejoin all groups on vlan devices */
-       list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
-               vlan_dev = __vlan_find_dev_deep(bond_dev, htons(ETH_P_8021Q),
-                                               vlan->vlan_id);
-               if (vlan_dev)
-                       __bond_resend_igmp_join_requests(vlan_dev);
+       if (!rtnl_trylock()) {
+               queue_delayed_work(bond->wq, &bond->mcast_work, 1);
+               return;
        }
-       rcu_read_unlock();
+       call_netdevice_notifiers(NETDEV_RESEND_IGMP, bond->dev);
+       rtnl_unlock();
 
        /* We use curr_slave_lock to protect against concurrent access to
         * igmp_retrans from multiple running instances of this function and
@@ -769,7 +589,6 @@ static void bond_resend_igmp_join_requests(struct bonding *bond)
                queue_delayed_work(bond->wq, &bond->mcast_work, HZ/5);
        }
        write_unlock_bh(&bond->curr_slave_lock);
-       read_unlock(&bond->lock);
 }
 
 static void bond_resend_igmp_join_requests_delayed(struct work_struct *work)
@@ -808,6 +627,8 @@ static void bond_hw_addr_flush(struct net_device *bond_dev,
 static void bond_hw_addr_swap(struct bonding *bond, struct slave *new_active,
                              struct slave *old_active)
 {
+       ASSERT_RTNL();
+
        if (old_active) {
                if (bond->dev->flags & IFF_PROMISC)
                        dev_set_promiscuity(old_active->dev, -1);
@@ -966,9 +787,8 @@ static struct slave *bond_find_best_slave(struct bonding *bond)
        new_active = bond->curr_active_slave;
 
        if (!new_active) { /* there were no active slaves left */
-               if (bond->slave_cnt > 0)   /* found one slave */
-                       new_active = bond->first_slave;
-               else
+               new_active = bond_first_slave(bond);
+               if (!new_active)
                        return NULL; /* still no slave, return NULL */
        }
 
@@ -1008,7 +828,6 @@ static bool bond_should_notify_peers(struct bonding *bond)
            test_bit(__LINK_STATE_LINKWATCH_PENDING, &slave->dev->state))
                return false;
 
-       bond->send_peer_notif--;
        return true;
 }
 
@@ -1071,7 +890,7 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
                if (new_active)
                        bond_set_slave_active_flags(new_active);
        } else {
-               bond->curr_active_slave = new_active;
+               rcu_assign_pointer(bond->curr_active_slave, new_active);
        }
 
        if (bond->params.mode == BOND_MODE_ACTIVEBACKUP) {
@@ -1115,7 +934,7 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
            ((USES_PRIMARY(bond->params.mode) && new_active) ||
             bond->params.mode == BOND_MODE_ROUNDROBIN)) {
                bond->igmp_retrans = bond->params.resend_igmp;
-               queue_delayed_work(bond->wq, &bond->mcast_work, 0);
+               queue_delayed_work(bond->wq, &bond->mcast_work, 1);
        }
 }
 
@@ -1161,17 +980,7 @@ void bond_select_active_slave(struct bonding *bond)
  */
 static void bond_attach_slave(struct bonding *bond, struct slave *new_slave)
 {
-       if (bond->first_slave == NULL) { /* attaching the first slave */
-               new_slave->next = new_slave;
-               new_slave->prev = new_slave;
-               bond->first_slave = new_slave;
-       } else {
-               new_slave->next = bond->first_slave;
-               new_slave->prev = bond->first_slave->prev;
-               new_slave->next->prev = new_slave;
-               new_slave->prev->next = new_slave;
-       }
-
+       list_add_tail_rcu(&new_slave->list, &bond->slave_list);
        bond->slave_cnt++;
 }
 
@@ -1187,22 +996,7 @@ static void bond_attach_slave(struct bonding *bond, struct slave *new_slave)
  */
 static void bond_detach_slave(struct bonding *bond, struct slave *slave)
 {
-       if (slave->next)
-               slave->next->prev = slave->prev;
-
-       if (slave->prev)
-               slave->prev->next = slave->next;
-
-       if (bond->first_slave == slave) { /* slave is the first slave */
-               if (bond->slave_cnt > 1) { /* there are more slave */
-                       bond->first_slave = slave->next;
-               } else {
-                       bond->first_slave = NULL; /* slave was the last one */
-               }
-       }
-
-       slave->next = NULL;
-       slave->prev = NULL;
+       list_del_rcu(&slave->list);
        bond->slave_cnt--;
 }
 
@@ -1249,47 +1043,31 @@ static void bond_poll_controller(struct net_device *bond_dev)
 {
 }
 
-static void __bond_netpoll_cleanup(struct bonding *bond)
+static void bond_netpoll_cleanup(struct net_device *bond_dev)
 {
+       struct bonding *bond = netdev_priv(bond_dev);
        struct slave *slave;
-       int i;
 
-       bond_for_each_slave(bond, slave, i)
+       bond_for_each_slave(bond, slave)
                if (IS_UP(slave->dev))
                        slave_disable_netpoll(slave);
 }
-static void bond_netpoll_cleanup(struct net_device *bond_dev)
-{
-       struct bonding *bond = netdev_priv(bond_dev);
-
-       read_lock(&bond->lock);
-       __bond_netpoll_cleanup(bond);
-       read_unlock(&bond->lock);
-}
 
 static int bond_netpoll_setup(struct net_device *dev, struct netpoll_info *ni, gfp_t gfp)
 {
        struct bonding *bond = netdev_priv(dev);
        struct slave *slave;
-       int i, err = 0;
+       int err = 0;
 
-       read_lock(&bond->lock);
-       bond_for_each_slave(bond, slave, i) {
+       bond_for_each_slave(bond, slave) {
                err = slave_enable_netpoll(slave);
                if (err) {
-                       __bond_netpoll_cleanup(bond);
+                       bond_netpoll_cleanup(dev);
                        break;
                }
        }
-       read_unlock(&bond->lock);
        return err;
 }
-
-static struct netpoll_info *bond_netpoll_info(struct bonding *bond)
-{
-       return bond->dev->npinfo;
-}
-
 #else
 static inline int slave_enable_netpoll(struct slave *slave)
 {
@@ -1306,34 +1084,29 @@ static void bond_netpoll_cleanup(struct net_device *bond_dev)
 /*---------------------------------- IOCTL ----------------------------------*/
 
 static netdev_features_t bond_fix_features(struct net_device *dev,
-       netdev_features_t features)
+                                          netdev_features_t features)
 {
-       struct slave *slave;
        struct bonding *bond = netdev_priv(dev);
        netdev_features_t mask;
-       int i;
-
-       read_lock(&bond->lock);
+       struct slave *slave;
 
-       if (!bond->first_slave) {
+       if (list_empty(&bond->slave_list)) {
                /* Disable adding VLANs to empty bond. But why? --mq */
                features |= NETIF_F_VLAN_CHALLENGED;
-               goto out;
+               return features;
        }
 
        mask = features;
        features &= ~NETIF_F_ONE_FOR_ALL;
        features |= NETIF_F_ALL_FOR_ALL;
 
-       bond_for_each_slave(bond, slave, i) {
+       bond_for_each_slave(bond, slave) {
                features = netdev_increment_features(features,
                                                     slave->dev->features,
                                                     mask);
        }
        features = netdev_add_tso_features(features, mask);
 
-out:
-       read_unlock(&bond->lock);
        return features;
 }
 
@@ -1343,21 +1116,18 @@ out:
 
 static void bond_compute_features(struct bonding *bond)
 {
-       struct slave *slave;
-       struct net_device *bond_dev = bond->dev;
+       unsigned int flags, dst_release_flag = IFF_XMIT_DST_RELEASE;
        netdev_features_t vlan_features = BOND_VLAN_FEATURES;
        unsigned short max_hard_header_len = ETH_HLEN;
        unsigned int gso_max_size = GSO_MAX_SIZE;
+       struct net_device *bond_dev = bond->dev;
        u16 gso_max_segs = GSO_MAX_SEGS;
-       int i;
-       unsigned int flags, dst_release_flag = IFF_XMIT_DST_RELEASE;
-
-       read_lock(&bond->lock);
+       struct slave *slave;
 
-       if (!bond->first_slave)
+       if (list_empty(&bond->slave_list))
                goto done;
 
-       bond_for_each_slave(bond, slave, i) {
+       bond_for_each_slave(bond, slave) {
                vlan_features = netdev_increment_features(vlan_features,
                        slave->dev->vlan_features, BOND_VLAN_FEATURES);
 
@@ -1378,8 +1148,6 @@ done:
        flags = bond_dev->priv_flags & ~IFF_XMIT_DST_RELEASE;
        bond_dev->priv_flags = flags | dst_release_flag;
 
-       read_unlock(&bond->lock);
-
        netdev_change_features(bond_dev);
 }
 
@@ -1545,7 +1313,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
         * bond ether type mutual exclusion - don't allow slaves of dissimilar
         * ether type (eg ARPHRD_ETHER and ARPHRD_INFINIBAND) share the same bond
         */
-       if (bond->slave_cnt == 0) {
+       if (list_empty(&bond->slave_list)) {
                if (bond_dev->type != slave_dev->type) {
                        pr_debug("%s: change device type from %d to %d\n",
                                 bond_dev->name,
@@ -1584,7 +1352,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
        }
 
        if (slave_ops->ndo_set_mac_address == NULL) {
-               if (bond->slave_cnt == 0) {
+               if (list_empty(&bond->slave_list)) {
                        pr_warning("%s: Warning: The first slave device specified does not support setting the MAC address. Setting fail_over_mac to active.",
                                   bond_dev->name);
                        bond->params.fail_over_mac = BOND_FOM_ACTIVE;
@@ -1600,7 +1368,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
 
        /* If this is the first slave, then we need to set the master's hardware
         * address to be the same as the slave's. */
-       if (!bond->slave_cnt && bond->dev->addr_assign_type == NET_ADDR_RANDOM)
+       if (list_empty(&bond->slave_list) &&
+           bond->dev->addr_assign_type == NET_ADDR_RANDOM)
                bond_set_dev_addr(bond->dev, slave_dev);
 
        new_slave = kzalloc(sizeof(struct slave), GFP_KERNEL);
@@ -1608,7 +1377,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
                res = -ENOMEM;
                goto err_undo_flags;
        }
-
+       INIT_LIST_HEAD(&new_slave->list);
        /*
         * Set the new_slave's queue_id to be zero.  Queue ID mapping
         * is set via sysfs or module option if desired.
@@ -1703,7 +1472,12 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
                dev_mc_add(slave_dev, lacpdu_multicast);
        }
 
-       bond_add_vlans_on_slave(bond, slave_dev);
+       res = vlan_vids_add_by_dev(slave_dev, bond_dev);
+       if (res) {
+               pr_err("%s: Error: Couldn't add bond vlan ids to %s\n",
+                      bond_dev->name, slave_dev->name);
+               goto err_close;
+       }
 
        write_lock_bh(&bond->lock);
 
@@ -1794,15 +1568,18 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
                 */
                bond_set_slave_inactive_flags(new_slave);
                /* if this is the first slave */
-               if (bond->slave_cnt == 1) {
+               if (bond_first_slave(bond) == new_slave) {
                        SLAVE_AD_INFO(new_slave).id = 1;
                        /* Initialize AD with the number of times that the AD timer is called in 1 second
                         * can be called only after the mac address of the bond is set
                         */
                        bond_3ad_initialize(bond, 1000/AD_TIMER_INTERVAL);
                } else {
+                       struct slave *prev_slave;
+
+                       prev_slave = bond_prev_slave(bond, new_slave);
                        SLAVE_AD_INFO(new_slave).id =
-                               SLAVE_AD_INFO(new_slave->prev).id + 1;
+                               SLAVE_AD_INFO(prev_slave).id + 1;
                }
 
                bond_3ad_bind_slave(new_slave);
@@ -1824,7 +1601,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
                 * so we can change it without calling change_active_interface()
                 */
                if (!bond->curr_active_slave && new_slave->link == BOND_LINK_UP)
-                       bond->curr_active_slave = new_slave;
+                       rcu_assign_pointer(bond->curr_active_slave, new_slave);
 
                break;
        } /* switch(bond_mode) */
@@ -1834,7 +1611,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
        bond_set_carrier(bond);
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
-       slave_dev->npinfo = bond_netpoll_info(bond);
+       slave_dev->npinfo = bond->dev->npinfo;
        if (slave_dev->npinfo) {
                if (slave_enable_netpoll(new_slave)) {
                        read_unlock(&bond->lock);
@@ -1876,7 +1653,7 @@ err_detach:
        if (!USES_PRIMARY(bond->params.mode))
                bond_hw_addr_flush(bond_dev, slave_dev);
 
-       bond_del_vlans_from_slave(bond, slave_dev);
+       vlan_vids_del_by_dev(slave_dev, bond_dev);
        write_lock_bh(&bond->lock);
        bond_detach_slave(bond, new_slave);
        if (bond->primary_slave == new_slave)
@@ -1921,7 +1698,7 @@ err_free:
 err_undo_flags:
        bond_compute_features(bond);
        /* Enslave of first slave has failed and we need to fix master's mac */
-       if (bond->slave_cnt == 0 &&
+       if (list_empty(&bond->slave_list) &&
            ether_addr_equal(bond_dev->dev_addr, slave_dev->dev_addr))
                eth_hw_addr_random(bond_dev);
 
@@ -1947,6 +1724,7 @@ static int __bond_release_one(struct net_device *bond_dev,
        struct bonding *bond = netdev_priv(bond_dev);
        struct slave *slave, *oldcurrent;
        struct sockaddr addr;
+       int old_flags = bond_dev->flags;
        netdev_features_t old_features = bond_dev->features;
 
        /* slave is not a slave or master is not master of this slave */
@@ -1977,15 +1755,6 @@ static int __bond_release_one(struct net_device *bond_dev,
        netdev_rx_handler_unregister(slave_dev);
        write_lock_bh(&bond->lock);
 
-       if (!all && !bond->params.fail_over_mac) {
-               if (ether_addr_equal(bond_dev->dev_addr, slave->perm_hwaddr) &&
-                   bond->slave_cnt > 1)
-                       pr_warning("%s: Warning: the permanent HWaddr of %s - %pM - is still in use by %s. Set the HWaddr of %s to a different address to avoid conflicts.\n",
-                                  bond_dev->name, slave_dev->name,
-                                  slave->perm_hwaddr,
-                                  bond_dev->name, slave_dev->name);
-       }
-
        /* Inform AD package of unbinding of slave. */
        if (bond->params.mode == BOND_MODE_8023AD) {
                /* must be called before the slave is
@@ -2006,6 +1775,15 @@ static int __bond_release_one(struct net_device *bond_dev,
        /* release the slave from its bond */
        bond_detach_slave(bond, slave);
 
+       if (!all && !bond->params.fail_over_mac) {
+               if (ether_addr_equal(bond_dev->dev_addr, slave->perm_hwaddr) &&
+                   !list_empty(&bond->slave_list))
+                       pr_warn("%s: Warning: the permanent HWaddr of %s - %pM - is still in use by %s. Set the HWaddr of %s to a different address to avoid conflicts.\n",
+                                  bond_dev->name, slave_dev->name,
+                                  slave->perm_hwaddr,
+                                  bond_dev->name, slave_dev->name);
+       }
+
        if (bond->primary_slave == slave)
                bond->primary_slave = NULL;
 
@@ -2024,7 +1802,7 @@ static int __bond_release_one(struct net_device *bond_dev,
        }
 
        if (all) {
-               bond->curr_active_slave = NULL;
+               rcu_assign_pointer(bond->curr_active_slave, NULL);
        } else if (oldcurrent == slave) {
                /*
                 * Note that we hold RTNL over this sequence, so there
@@ -2042,11 +1820,11 @@ static int __bond_release_one(struct net_device *bond_dev,
                write_lock_bh(&bond->lock);
        }
 
-       if (bond->slave_cnt == 0) {
+       if (list_empty(&bond->slave_list)) {
                bond_set_carrier(bond);
                eth_hw_addr_random(bond_dev);
 
-               if (bond_vlan_used(bond)) {
+               if (vlan_uses_dev(bond_dev)) {
                        pr_warning("%s: Warning: clearing HW address of %s while it still has VLANs.\n",
                                   bond_dev->name, bond_dev->name);
                        pr_warning("%s: When re-adding slaves, make sure the bond's HW address matches its VLANs'.\n",
@@ -2056,8 +1834,9 @@ static int __bond_release_one(struct net_device *bond_dev,
 
        write_unlock_bh(&bond->lock);
        unblock_netpoll_tx();
+       synchronize_rcu();
 
-       if (bond->slave_cnt == 0) {
+       if (list_empty(&bond->slave_list)) {
                call_netdevice_notifiers(NETDEV_CHANGEADDR, bond->dev);
                call_netdevice_notifiers(NETDEV_RELEASE, bond->dev);
        }
@@ -2071,18 +1850,24 @@ static int __bond_release_one(struct net_device *bond_dev,
        /* must do this from outside any spinlocks */
        bond_destroy_slave_symlinks(bond_dev, slave_dev);
 
-       bond_del_vlans_from_slave(bond, slave_dev);
+       vlan_vids_del_by_dev(slave_dev, bond_dev);
 
        /* 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 */
-               if (bond_dev->flags & IFF_PROMISC)
+               /* unset promiscuity level from slave
+                * NOTE: The NETDEV_CHANGEADDR call above may change the value
+                * of the IFF_PROMISC flag in the bond_dev, but we need the
+                * value of that flag before that change, as that was the value
+                * when this slave was attached, so we cache at the start of the
+                * function and use it here. Same goes for ALLMULTI below
+                */
+               if (old_flags & IFF_PROMISC)
                        dev_set_promiscuity(slave_dev, -1);
 
                /* unset allmulti level from slave */
-               if (bond_dev->flags & IFF_ALLMULTI)
+               if (old_flags & IFF_ALLMULTI)
                        dev_set_allmulti(slave_dev, -1);
 
                bond_hw_addr_flush(bond_dev, slave_dev);
@@ -2128,7 +1913,7 @@ static int  bond_release_and_destroy(struct net_device *bond_dev,
        int ret;
 
        ret = bond_release(bond_dev, slave_dev);
-       if ((ret == 0) && (bond->slave_cnt == 0)) {
+       if (ret == 0 && list_empty(&bond->slave_list)) {
                bond_dev->priv_flags |= IFF_DISABLE_NETPOLL;
                pr_info("%s: destroying bond %s.\n",
                        bond_dev->name, bond_dev->name);
@@ -2165,23 +1950,19 @@ static int bond_ioctl_change_active(struct net_device *bond_dev, struct net_devi
 
        read_lock(&bond->lock);
 
-       read_lock(&bond->curr_slave_lock);
        old_active = bond->curr_active_slave;
-       read_unlock(&bond->curr_slave_lock);
-
        new_active = bond_get_slave_by_dev(bond, slave_dev);
-
        /*
         * Changing to the current active: do nothing; return success.
         */
-       if (new_active && (new_active == old_active)) {
+       if (new_active && new_active == old_active) {
                read_unlock(&bond->lock);
                return 0;
        }
 
-       if ((new_active) &&
-           (old_active) &&
-           (new_active->link == BOND_LINK_UP) &&
+       if (new_active &&
+           old_active &&
+           new_active->link == BOND_LINK_UP &&
            IS_UP(new_active->dev)) {
                block_netpoll_tx();
                write_lock_bh(&bond->curr_slave_lock);
@@ -2213,13 +1994,12 @@ static int bond_info_query(struct net_device *bond_dev, struct ifbond *info)
 static int bond_slave_info_query(struct net_device *bond_dev, struct ifslave *info)
 {
        struct bonding *bond = netdev_priv(bond_dev);
+       int i = 0, res = -ENODEV;
        struct slave *slave;
-       int i, res = -ENODEV;
 
        read_lock(&bond->lock);
-
-       bond_for_each_slave(bond, slave, i) {
-               if (i == (int)info->slave_id) {
+       bond_for_each_slave(bond, slave) {
+               if (i++ == (int)info->slave_id) {
                        res = 0;
                        strcpy(info->slave_name, slave->dev->name);
                        info->link = slave->link;
@@ -2228,7 +2008,6 @@ static int bond_slave_info_query(struct net_device *bond_dev, struct ifslave *in
                        break;
                }
        }
-
        read_unlock(&bond->lock);
 
        return res;
@@ -2239,13 +2018,13 @@ static int bond_slave_info_query(struct net_device *bond_dev, struct ifslave *in
 
 static int bond_miimon_inspect(struct bonding *bond)
 {
+       int link_state, commit = 0;
        struct slave *slave;
-       int i, link_state, commit = 0;
        bool ignore_updelay;
 
        ignore_updelay = !bond->curr_active_slave ? true : false;
 
-       bond_for_each_slave(bond, slave, i) {
+       bond_for_each_slave(bond, slave) {
                slave->new_link = BOND_LINK_NOCHANGE;
 
                link_state = bond_check_dev_link(bond, slave->dev, 0);
@@ -2340,9 +2119,8 @@ static int bond_miimon_inspect(struct bonding *bond)
 static void bond_miimon_commit(struct bonding *bond)
 {
        struct slave *slave;
-       int i;
 
-       bond_for_each_slave(bond, slave, i) {
+       bond_for_each_slave(bond, slave) {
                switch (slave->new_link) {
                case BOND_LINK_NOCHANGE:
                        continue;
@@ -2447,7 +2225,7 @@ void bond_mii_monitor(struct work_struct *work)
 
        delay = msecs_to_jiffies(bond->params.miimon);
 
-       if (bond->slave_cnt == 0)
+       if (list_empty(&bond->slave_list))
                goto re_arm;
 
        should_notify_peers = bond_should_notify_peers(bond);
@@ -2479,35 +2257,32 @@ re_arm:
        read_unlock(&bond->lock);
 
        if (should_notify_peers) {
-               if (!rtnl_trylock()) {
-                       read_lock(&bond->lock);
-                       bond->send_peer_notif++;
-                       read_unlock(&bond->lock);
+               if (!rtnl_trylock())
                        return;
-               }
                call_netdevice_notifiers(NETDEV_NOTIFY_PEERS, bond->dev);
                rtnl_unlock();
        }
 }
 
-static int bond_has_this_ip(struct bonding *bond, __be32 ip)
+static bool bond_has_this_ip(struct bonding *bond, __be32 ip)
 {
-       struct vlan_entry *vlan;
-       struct net_device *vlan_dev;
+       struct net_device *upper;
+       struct list_head *iter;
+       bool ret = false;
 
        if (ip == bond_confirm_addr(bond->dev, 0, ip))
-               return 1;
+               return true;
 
-       list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
-               rcu_read_lock();
-               vlan_dev = __vlan_find_dev_deep(bond->dev, htons(ETH_P_8021Q),
-                                               vlan->vlan_id);
-               rcu_read_unlock();
-               if (vlan_dev && ip == bond_confirm_addr(vlan_dev, 0, ip))
-                       return 1;
+       rcu_read_lock();
+       netdev_for_each_upper_dev_rcu(bond->dev, upper, iter) {
+               if (ip == bond_confirm_addr(upper, 0, ip)) {
+                       ret = true;
+                       break;
+               }
        }
+       rcu_read_unlock();
 
-       return 0;
+       return ret;
 }
 
 /*
@@ -2542,81 +2317,79 @@ static void bond_arp_send(struct net_device *slave_dev, int arp_op, __be32 dest_
 
 static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
 {
-       int i, vlan_id;
-       __be32 *targets = bond->params.arp_targets;
-       struct vlan_entry *vlan;
-       struct net_device *vlan_dev = NULL;
+       struct net_device *upper, *vlan_upper;
+       struct list_head *iter, *vlan_iter;
        struct rtable *rt;
+       __be32 *targets = bond->params.arp_targets, addr;
+       int i, vlan_id;
 
-       for (i = 0; (i < BOND_MAX_ARP_TARGETS); i++) {
-               __be32 addr;
-               if (!targets[i])
-                       break;
+       for (i = 0; i < BOND_MAX_ARP_TARGETS && targets[i]; i++) {
                pr_debug("basa: target %pI4\n", &targets[i]);
-               if (!bond_vlan_used(bond)) {
-                       pr_debug("basa: empty vlan: arp_send\n");
-                       addr = bond_confirm_addr(bond->dev, targets[i], 0);
-                       bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i],
-                                     addr, 0);
-                       continue;
-               }
 
-               /*
-                * If VLANs are configured, we do a route lookup to
-                * determine which VLAN interface would be used, so we
-                * can tag the ARP with the proper VLAN tag.
-                */
+               /* Find out through which dev should the packet go */
                rt = ip_route_output(dev_net(bond->dev), targets[i], 0,
                                     RTO_ONLINK, 0);
                if (IS_ERR(rt)) {
-                       if (net_ratelimit()) {
-                               pr_warning("%s: no route to arp_ip_target %pI4\n",
-                                          bond->dev->name, &targets[i]);
-                       }
+                       pr_debug("%s: no route to arp_ip_target %pI4\n",
+                                bond->dev->name, &targets[i]);
                        continue;
                }
 
-               /*
-                * This target is not on a VLAN
+               vlan_id = 0;
+
+               /* bond device itself */
+               if (rt->dst.dev == bond->dev)
+                       goto found;
+
+               rcu_read_lock();
+               /* first we search only for vlan devices. for every vlan
+                * found we verify its upper dev list, searching for the
+                * rt->dst.dev. If found we save the tag of the vlan and
+                * proceed to send the packet.
+                *
+                * TODO: QinQ?
                 */
-               if (rt->dst.dev == bond->dev) {
-                       ip_rt_put(rt);
-                       pr_debug("basa: rtdev == bond->dev: arp_send\n");
-                       addr = bond_confirm_addr(bond->dev, targets[i], 0);
-                       bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i],
-                                     addr, 0);
-                       continue;
+               netdev_for_each_upper_dev_rcu(bond->dev, vlan_upper, vlan_iter) {
+                       if (!is_vlan_dev(vlan_upper))
+                               continue;
+                       netdev_for_each_upper_dev_rcu(vlan_upper, upper, iter) {
+                               if (upper == rt->dst.dev) {
+                                       vlan_id = vlan_dev_vlan_id(vlan_upper);
+                                       rcu_read_unlock();
+                                       goto found;
+                               }
+                       }
                }
 
-               vlan_id = 0;
-               list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
-                       rcu_read_lock();
-                       vlan_dev = __vlan_find_dev_deep(bond->dev,
-                                                       htons(ETH_P_8021Q),
-                                                       vlan->vlan_id);
-                       rcu_read_unlock();
-                       if (vlan_dev == rt->dst.dev) {
-                               vlan_id = vlan->vlan_id;
-                               pr_debug("basa: vlan match on %s %d\n",
-                                      vlan_dev->name, vlan_id);
-                               break;
+               /* if the device we're looking for is not on top of any of
+                * our upper vlans, then just search for any dev that
+                * matches, and in case it's a vlan - save the id
+                */
+               netdev_for_each_upper_dev_rcu(bond->dev, upper, iter) {
+                       if (upper == rt->dst.dev) {
+                               /* if it's a vlan - get its VID */
+                               if (is_vlan_dev(upper))
+                                       vlan_id = vlan_dev_vlan_id(upper);
+
+                               rcu_read_unlock();
+                               goto found;
                        }
                }
+               rcu_read_unlock();
 
-               if (vlan_id && vlan_dev) {
-                       ip_rt_put(rt);
-                       addr = bond_confirm_addr(vlan_dev, targets[i], 0);
-                       bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i],
-                                     addr, vlan_id);
-                       continue;
-               }
+               /* Not our device - skip */
+               pr_debug("%s: no path to arp_ip_target %pI4 via rt.dev %s\n",
+                        bond->dev->name, &targets[i],
+                        rt->dst.dev ? rt->dst.dev->name : "NULL");
 
-               if (net_ratelimit()) {
-                       pr_warning("%s: no path to arp_ip_target %pI4 via rt.dev %s\n",
-                                  bond->dev->name, &targets[i],
-                                  rt->dst.dev ? rt->dst.dev->name : "NULL");
-               }
                ip_rt_put(rt);
+               continue;
+
+found:
+               addr = bond_confirm_addr(rt->dst.dev, targets[i], 0);
+               ip_rt_put(rt);
+               bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i],
+                             addr, vlan_id);
        }
 }
 
@@ -2638,8 +2411,8 @@ static void bond_validate_arp(struct bonding *bond, struct slave *slave, __be32
        slave->target_last_arp_rx[i] = jiffies;
 }
 
-static int bond_arp_rcv(const struct sk_buff *skb, struct bonding *bond,
-                       struct slave *slave)
+int bond_arp_rcv(const struct sk_buff *skb, struct bonding *bond,
+                struct slave *slave)
 {
        struct arphdr *arp = (struct arphdr *)skb->data;
        unsigned char *arp_ptr;
@@ -2713,6 +2486,20 @@ out_unlock:
        return RX_HANDLER_ANOTHER;
 }
 
+/* function to verify if we're in the arp_interval timeslice, returns true if
+ * (last_act - arp_interval) <= jiffies <= (last_act + mod * arp_interval +
+ * arp_interval/2) . the arp_interval/2 is needed for really fast networks.
+ */
+static bool bond_time_in_interval(struct bonding *bond, unsigned long last_act,
+                                 int mod)
+{
+       int delta_in_ticks = msecs_to_jiffies(bond->params.arp_interval);
+
+       return time_in_range(jiffies,
+                            last_act - delta_in_ticks,
+                            last_act + mod * delta_in_ticks + delta_in_ticks/2);
+}
+
 /*
  * this function is called regularly to monitor each slave's link
  * ensuring that traffic is being sent and received when arp monitoring
@@ -2726,21 +2513,13 @@ void bond_loadbalance_arp_mon(struct work_struct *work)
                                            arp_work.work);
        struct slave *slave, *oldcurrent;
        int do_failover = 0;
-       int delta_in_ticks, extra_ticks;
-       int i;
 
        read_lock(&bond->lock);
 
-       delta_in_ticks = msecs_to_jiffies(bond->params.arp_interval);
-       extra_ticks = delta_in_ticks / 2;
-
-       if (bond->slave_cnt == 0)
+       if (list_empty(&bond->slave_list))
                goto re_arm;
 
-       read_lock(&bond->curr_slave_lock);
        oldcurrent = bond->curr_active_slave;
-       read_unlock(&bond->curr_slave_lock);
-
        /* see if any of the previous devices are up now (i.e. they have
         * xmt and rcv traffic). the curr_active_slave does not come into
         * the picture unless it is null. also, slave->jiffies is not needed
@@ -2749,16 +2528,12 @@ void bond_loadbalance_arp_mon(struct work_struct *work)
         * TODO: what about up/down delay in arp mode? it wasn't here before
         *       so it can wait
         */
-       bond_for_each_slave(bond, slave, i) {
+       bond_for_each_slave(bond, slave) {
                unsigned long trans_start = dev_trans_start(slave->dev);
 
                if (slave->link != BOND_LINK_UP) {
-                       if (time_in_range(jiffies,
-                               trans_start - delta_in_ticks,
-                               trans_start + delta_in_ticks + extra_ticks) &&
-                           time_in_range(jiffies,
-                               slave->dev->last_rx - delta_in_ticks,
-                               slave->dev->last_rx + delta_in_ticks + extra_ticks)) {
+                       if (bond_time_in_interval(bond, trans_start, 1) &&
+                           bond_time_in_interval(bond, slave->dev->last_rx, 1)) {
 
                                slave->link  = BOND_LINK_UP;
                                bond_set_active_slave(slave);
@@ -2786,12 +2561,8 @@ void bond_loadbalance_arp_mon(struct work_struct *work)
                         * when the source ip is 0, so don't take the link down
                         * if we don't know our ip yet
                         */
-                       if (!time_in_range(jiffies,
-                               trans_start - delta_in_ticks,
-                               trans_start + 2 * delta_in_ticks + extra_ticks) ||
-                           !time_in_range(jiffies,
-                               slave->dev->last_rx - delta_in_ticks,
-                               slave->dev->last_rx + 2 * delta_in_ticks + extra_ticks)) {
+                       if (!bond_time_in_interval(bond, trans_start, 2) ||
+                           !bond_time_in_interval(bond, slave->dev->last_rx, 2)) {
 
                                slave->link  = BOND_LINK_DOWN;
                                bond_set_backup_slave(slave);
@@ -2831,7 +2602,8 @@ void bond_loadbalance_arp_mon(struct work_struct *work)
 
 re_arm:
        if (bond->params.arp_interval)
-               queue_delayed_work(bond->wq, &bond->arp_work, delta_in_ticks);
+               queue_delayed_work(bond->wq, &bond->arp_work,
+                                  msecs_to_jiffies(bond->params.arp_interval));
 
        read_unlock(&bond->lock);
 }
@@ -2844,32 +2616,21 @@ re_arm:
  *
  * Called with bond->lock held for read.
  */
-static int bond_ab_arp_inspect(struct bonding *bond, int delta_in_ticks)
+static int bond_ab_arp_inspect(struct bonding *bond)
 {
+       unsigned long trans_start, last_rx;
        struct slave *slave;
-       int i, commit = 0;
-       unsigned long trans_start;
-       int extra_ticks;
-
-       /* All the time comparisons below need some extra time. Otherwise, on
-        * fast networks the ARP probe/reply may arrive within the same jiffy
-        * as it was sent.  Then, the next time the ARP monitor is run, one
-        * arp_interval will already have passed in the comparisons.
-        */
-       extra_ticks = delta_in_ticks / 2;
+       int commit = 0;
 
-       bond_for_each_slave(bond, slave, i) {
+       bond_for_each_slave(bond, slave) {
                slave->new_link = BOND_LINK_NOCHANGE;
+               last_rx = slave_last_rx(bond, slave);
 
                if (slave->link != BOND_LINK_UP) {
-                       if (time_in_range(jiffies,
-                               slave_last_rx(bond, slave) - delta_in_ticks,
-                               slave_last_rx(bond, slave) + delta_in_ticks + extra_ticks)) {
-
+                       if (bond_time_in_interval(bond, last_rx, 1)) {
                                slave->new_link = BOND_LINK_UP;
                                commit++;
                        }
-
                        continue;
                }
 
@@ -2878,9 +2639,7 @@ static int bond_ab_arp_inspect(struct bonding *bond, int delta_in_ticks)
                 * active.  This avoids bouncing, as the last receive
                 * times need a full ARP monitor cycle to be updated.
                 */
-               if (time_in_range(jiffies,
-                                 slave->jiffies - delta_in_ticks,
-                                 slave->jiffies + 2 * delta_in_ticks + extra_ticks))
+               if (bond_time_in_interval(bond, slave->jiffies, 2))
                        continue;
 
                /*
@@ -2898,10 +2657,7 @@ static int bond_ab_arp_inspect(struct bonding *bond, int delta_in_ticks)
                 */
                if (!bond_is_active_slave(slave) &&
                    !bond->current_arp_slave &&
-                   !time_in_range(jiffies,
-                       slave_last_rx(bond, slave) - delta_in_ticks,
-                       slave_last_rx(bond, slave) + 3 * delta_in_ticks + extra_ticks)) {
-
+                   !bond_time_in_interval(bond, last_rx, 3)) {
                        slave->new_link = BOND_LINK_DOWN;
                        commit++;
                }
@@ -2914,13 +2670,8 @@ static int bond_ab_arp_inspect(struct bonding *bond, int delta_in_ticks)
                 */
                trans_start = dev_trans_start(slave->dev);
                if (bond_is_active_slave(slave) &&
-                   (!time_in_range(jiffies,
-                       trans_start - delta_in_ticks,
-                       trans_start + 2 * delta_in_ticks + extra_ticks) ||
-                    !time_in_range(jiffies,
-                       slave_last_rx(bond, slave) - delta_in_ticks,
-                       slave_last_rx(bond, slave) + 2 * delta_in_ticks + extra_ticks))) {
-
+                   (!bond_time_in_interval(bond, trans_start, 2) ||
+                    !bond_time_in_interval(bond, last_rx, 2))) {
                        slave->new_link = BOND_LINK_DOWN;
                        commit++;
                }
@@ -2935,24 +2686,21 @@ static int bond_ab_arp_inspect(struct bonding *bond, int delta_in_ticks)
  *
  * Called with RTNL and bond->lock for read.
  */
-static void bond_ab_arp_commit(struct bonding *bond, int delta_in_ticks)
+static void bond_ab_arp_commit(struct bonding *bond)
 {
-       struct slave *slave;
-       int i;
        unsigned long trans_start;
+       struct slave *slave;
 
-       bond_for_each_slave(bond, slave, i) {
+       bond_for_each_slave(bond, slave) {
                switch (slave->new_link) {
                case BOND_LINK_NOCHANGE:
                        continue;
 
                case BOND_LINK_UP:
                        trans_start = dev_trans_start(slave->dev);
-                       if ((!bond->curr_active_slave &&
-                            time_in_range(jiffies,
-                                          trans_start - delta_in_ticks,
-                                          trans_start + delta_in_ticks + delta_in_ticks / 2)) ||
-                           bond->curr_active_slave != slave) {
+                       if (bond->curr_active_slave != slave ||
+                           (!bond->curr_active_slave &&
+                            bond_time_in_interval(bond, trans_start, 1))) {
                                slave->link = BOND_LINK_UP;
                                if (bond->current_arp_slave) {
                                        bond_set_slave_inactive_flags(
@@ -3014,7 +2762,7 @@ do_failover:
  */
 static void bond_ab_arp_probe(struct bonding *bond)
 {
-       struct slave *slave;
+       struct slave *slave, *next_slave;
        int i;
 
        read_lock(&bond->curr_slave_lock);
@@ -3038,7 +2786,7 @@ static void bond_ab_arp_probe(struct bonding *bond)
         */
 
        if (!bond->current_arp_slave) {
-               bond->current_arp_slave = bond->first_slave;
+               bond->current_arp_slave = bond_first_slave(bond);
                if (!bond->current_arp_slave)
                        return;
        }
@@ -3046,7 +2794,8 @@ static void bond_ab_arp_probe(struct bonding *bond)
        bond_set_slave_inactive_flags(bond->current_arp_slave);
 
        /* search for next candidate */
-       bond_for_each_slave_from(bond, slave, i, bond->current_arp_slave->next) {
+       next_slave = bond_next_slave(bond, bond->current_arp_slave);
+       bond_for_each_slave_from(bond, slave, i, next_slave) {
                if (IS_UP(slave->dev)) {
                        slave->link = BOND_LINK_BACK;
                        bond_set_slave_active_flags(slave);
@@ -3087,12 +2836,12 @@ void bond_activebackup_arp_mon(struct work_struct *work)
 
        delta_in_ticks = msecs_to_jiffies(bond->params.arp_interval);
 
-       if (bond->slave_cnt == 0)
+       if (list_empty(&bond->slave_list))
                goto re_arm;
 
        should_notify_peers = bond_should_notify_peers(bond);
 
-       if (bond_ab_arp_inspect(bond, delta_in_ticks)) {
+       if (bond_ab_arp_inspect(bond)) {
                read_unlock(&bond->lock);
 
                /* Race avoidance with bond_close flush of workqueue */
@@ -3105,7 +2854,7 @@ void bond_activebackup_arp_mon(struct work_struct *work)
 
                read_lock(&bond->lock);
 
-               bond_ab_arp_commit(bond, delta_in_ticks);
+               bond_ab_arp_commit(bond);
 
                read_unlock(&bond->lock);
                rtnl_unlock();
@@ -3121,12 +2870,8 @@ re_arm:
        read_unlock(&bond->lock);
 
        if (should_notify_peers) {
-               if (!rtnl_trylock()) {
-                       read_lock(&bond->lock);
-                       bond->send_peer_notif++;
-                       read_unlock(&bond->lock);
+               if (!rtnl_trylock())
                        return;
-               }
                call_netdevice_notifiers(NETDEV_NOTIFY_PEERS, bond->dev);
                rtnl_unlock();
        }
@@ -3161,6 +2906,10 @@ static int bond_master_netdev_event(unsigned long event,
        case NETDEV_REGISTER:
                bond_create_proc_entry(event_bond);
                break;
+       case NETDEV_NOTIFY_PEERS:
+               if (event_bond->send_peer_notif)
+                       event_bond->send_peer_notif--;
+               break;
        default:
                break;
        }
@@ -3234,6 +2983,10 @@ static int bond_slave_netdev_event(unsigned long event,
        case NETDEV_FEAT_CHANGE:
                bond_compute_features(bond);
                break;
+       case NETDEV_RESEND_IGMP:
+               /* Propagate to master device */
+               call_netdevice_notifiers(event, slave->bond->dev);
+               break;
        default:
                break;
        }
@@ -3403,13 +3156,12 @@ static int bond_open(struct net_device *bond_dev)
 {
        struct bonding *bond = netdev_priv(bond_dev);
        struct slave *slave;
-       int i;
 
        /* reset slave->backup and slave->inactive */
        read_lock(&bond->lock);
-       if (bond->slave_cnt > 0) {
+       if (!list_empty(&bond->slave_list)) {
                read_lock(&bond->curr_slave_lock);
-               bond_for_each_slave(bond, slave, i) {
+               bond_for_each_slave(bond, slave) {
                        if ((bond->params.mode == BOND_MODE_ACTIVEBACKUP)
                                && (slave != bond->curr_active_slave)) {
                                bond_set_slave_inactive_flags(slave);
@@ -3455,17 +3207,10 @@ static int bond_close(struct net_device *bond_dev)
 {
        struct bonding *bond = netdev_priv(bond_dev);
 
-       write_lock_bh(&bond->lock);
-       bond->send_peer_notif = 0;
-       write_unlock_bh(&bond->lock);
-
        bond_work_cancel_all(bond);
-       if (bond_is_lb(bond)) {
-               /* Must be called only after all
-                * slaves have been released
-                */
+       bond->send_peer_notif = 0;
+       if (bond_is_lb(bond))
                bond_alb_deinitialize(bond);
-       }
        bond->recv_probe = NULL;
 
        return 0;
@@ -3477,13 +3222,11 @@ static struct rtnl_link_stats64 *bond_get_stats(struct net_device *bond_dev,
        struct bonding *bond = netdev_priv(bond_dev);
        struct rtnl_link_stats64 temp;
        struct slave *slave;
-       int i;
 
        memset(stats, 0, sizeof(*stats));
 
        read_lock_bh(&bond->lock);
-
-       bond_for_each_slave(bond, slave, i) {
+       bond_for_each_slave(bond, slave) {
                const struct rtnl_link_stats64 *sstats =
                        dev_get_stats(slave->dev, &temp);
 
@@ -3513,7 +3256,6 @@ static struct rtnl_link_stats64 *bond_get_stats(struct net_device *bond_dev,
                stats->tx_heartbeat_errors += sstats->tx_heartbeat_errors;
                stats->tx_window_errors += sstats->tx_window_errors;
        }
-
        read_unlock_bh(&bond->lock);
 
        return stats;
@@ -3652,41 +3394,35 @@ static void bond_set_rx_mode(struct net_device *bond_dev)
 {
        struct bonding *bond = netdev_priv(bond_dev);
        struct slave *slave;
-       int i;
 
-       read_lock(&bond->lock);
+       ASSERT_RTNL();
 
        if (USES_PRIMARY(bond->params.mode)) {
-               read_lock(&bond->curr_slave_lock);
-               slave = bond->curr_active_slave;
+               slave = rtnl_dereference(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) {
+               bond_for_each_slave(bond, slave) {
                        dev_uc_sync_multiple(slave->dev, bond_dev);
                        dev_mc_sync_multiple(slave->dev, bond_dev);
                }
        }
-
-       read_unlock(&bond->lock);
 }
 
 static int bond_neigh_init(struct neighbour *n)
 {
        struct bonding *bond = netdev_priv(n->dev);
-       struct slave *slave = bond->first_slave;
        const struct net_device_ops *slave_ops;
        struct neigh_parms parms;
+       struct slave *slave;
        int ret;
 
+       slave = bond_first_slave(bond);
        if (!slave)
                return 0;
-
        slave_ops = slave->dev->netdev_ops;
-
        if (!slave_ops->ndo_neigh_setup)
                return 0;
 
@@ -3735,9 +3471,8 @@ static int bond_neigh_setup(struct net_device *dev,
 static int bond_change_mtu(struct net_device *bond_dev, int new_mtu)
 {
        struct bonding *bond = netdev_priv(bond_dev);
-       struct slave *slave, *stop_at;
+       struct slave *slave;
        int res = 0;
-       int i;
 
        pr_debug("bond=%p, name=%s, new_mtu=%d\n", bond,
                 (bond_dev ? bond_dev->name : "None"), new_mtu);
@@ -3757,10 +3492,10 @@ static int bond_change_mtu(struct net_device *bond_dev, int new_mtu)
         * call to the base driver.
         */
 
-       bond_for_each_slave(bond, slave, i) {
+       bond_for_each_slave(bond, slave) {
                pr_debug("s %p s->p %p c_m %p\n",
                         slave,
-                        slave->prev,
+                        bond_prev_slave(bond, slave),
                         slave->dev->netdev_ops->ndo_change_mtu);
 
                res = dev_set_mtu(slave->dev, new_mtu);
@@ -3785,8 +3520,7 @@ static int bond_change_mtu(struct net_device *bond_dev, int new_mtu)
 
 unwind:
        /* unwind from head to the slave that failed */
-       stop_at = slave;
-       bond_for_each_slave_from_to(bond, slave, i, bond->first_slave, stop_at) {
+       bond_for_each_slave_continue_reverse(bond, slave) {
                int tmp_res;
 
                tmp_res = dev_set_mtu(slave->dev, bond_dev->mtu);
@@ -3810,9 +3544,8 @@ static int bond_set_mac_address(struct net_device *bond_dev, void *addr)
 {
        struct bonding *bond = netdev_priv(bond_dev);
        struct sockaddr *sa = addr, tmp_sa;
-       struct slave *slave, *stop_at;
+       struct slave *slave;
        int res = 0;
-       int i;
 
        if (bond->params.mode == BOND_MODE_ALB)
                return bond_alb_set_mac_address(bond_dev, addr);
@@ -3845,7 +3578,7 @@ static int bond_set_mac_address(struct net_device *bond_dev, void *addr)
         * call to the base driver.
         */
 
-       bond_for_each_slave(bond, slave, i) {
+       bond_for_each_slave(bond, slave) {
                const struct net_device_ops *slave_ops = slave->dev->netdev_ops;
                pr_debug("slave %p %s\n", slave, slave->dev->name);
 
@@ -3877,8 +3610,7 @@ unwind:
        tmp_sa.sa_family = bond_dev->type;
 
        /* unwind from head to the slave that failed */
-       stop_at = slave;
-       bond_for_each_slave_from_to(bond, slave, i, bond->first_slave, stop_at) {
+       bond_for_each_slave_continue_reverse(bond, slave) {
                int tmp_res;
 
                tmp_res = dev_set_mac_address(slave->dev, &tmp_sa);
@@ -3891,12 +3623,50 @@ unwind:
        return res;
 }
 
+/**
+ * bond_xmit_slave_id - transmit skb through slave with slave_id
+ * @bond: bonding device that is transmitting
+ * @skb: buffer to transmit
+ * @slave_id: slave id up to slave_cnt-1 through which to transmit
+ *
+ * This function tries to transmit through slave with slave_id but in case
+ * it fails, it tries to find the first available slave for transmission.
+ * The skb is consumed in all cases, thus the function is void.
+ */
+void bond_xmit_slave_id(struct bonding *bond, struct sk_buff *skb, int slave_id)
+{
+       struct slave *slave;
+       int i = slave_id;
+
+       /* Here we start from the slave with slave_id */
+       bond_for_each_slave_rcu(bond, slave) {
+               if (--i < 0) {
+                       if (slave_can_tx(slave)) {
+                               bond_dev_queue_xmit(bond, skb, slave->dev);
+                               return;
+                       }
+               }
+       }
+
+       /* Here we start from the first slave up to slave_id */
+       i = slave_id;
+       bond_for_each_slave_rcu(bond, slave) {
+               if (--i < 0)
+                       break;
+               if (slave_can_tx(slave)) {
+                       bond_dev_queue_xmit(bond, skb, slave->dev);
+                       return;
+               }
+       }
+       /* no slave that can tx has been found */
+       kfree_skb(skb);
+}
+
 static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *bond_dev)
 {
        struct bonding *bond = netdev_priv(bond_dev);
-       struct slave *slave, *start_at;
-       int i, slave_no, res = 1;
        struct iphdr *iph = ip_hdr(skb);
+       struct slave *slave;
 
        /*
         * Start with the curr_active_slave that joined the bond as the
@@ -3905,50 +3675,20 @@ static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *bond_dev
         * send the join/membership reports.  The curr_active_slave found
         * will send all of this type of traffic.
         */
-       if ((iph->protocol == IPPROTO_IGMP) &&
-           (skb->protocol == htons(ETH_P_IP))) {
-
-               read_lock(&bond->curr_slave_lock);
-               slave = bond->curr_active_slave;
-               read_unlock(&bond->curr_slave_lock);
-
-               if (!slave)
-                       goto out;
+       if (iph->protocol == IPPROTO_IGMP && skb->protocol == htons(ETH_P_IP)) {
+               slave = rcu_dereference(bond->curr_active_slave);
+               if (slave && slave_can_tx(slave))
+                       bond_dev_queue_xmit(bond, skb, slave->dev);
+               else
+                       bond_xmit_slave_id(bond, skb, 0);
        } else {
-               /*
-                * Concurrent TX may collide on rr_tx_counter; we accept
-                * that as being rare enough not to justify using an
-                * atomic op here.
-                */
-               slave_no = bond->rr_tx_counter++ % bond->slave_cnt;
-
-               bond_for_each_slave(bond, slave, i) {
-                       slave_no--;
-                       if (slave_no < 0)
-                               break;
-               }
-       }
-
-       start_at = slave;
-       bond_for_each_slave_from(bond, slave, i, start_at) {
-               if (IS_UP(slave->dev) &&
-                   (slave->link == BOND_LINK_UP) &&
-                   bond_is_active_slave(slave)) {
-                       res = bond_dev_queue_xmit(bond, skb, slave->dev);
-                       break;
-               }
-       }
-
-out:
-       if (res) {
-               /* no suitable interface, frame not sent */
-               kfree_skb(skb);
+               bond_xmit_slave_id(bond, skb,
+                                  bond->rr_tx_counter++ % bond->slave_cnt);
        }
 
        return NETDEV_TX_OK;
 }
 
-
 /*
  * in active-backup mode, we know that bond->curr_active_slave is always valid if
  * the bond has a usable interface.
@@ -3956,18 +3696,12 @@ out:
 static int bond_xmit_activebackup(struct sk_buff *skb, struct net_device *bond_dev)
 {
        struct bonding *bond = netdev_priv(bond_dev);
-       int res = 1;
-
-       read_lock(&bond->curr_slave_lock);
-
-       if (bond->curr_active_slave)
-               res = bond_dev_queue_xmit(bond, skb,
-                       bond->curr_active_slave->dev);
-
-       read_unlock(&bond->curr_slave_lock);
+       struct slave *slave;
 
-       if (res)
-               /* no suitable interface, frame not sent */
+       slave = rcu_dereference(bond->curr_active_slave);
+       if (slave)
+               bond_dev_queue_xmit(bond, skb, slave->dev);
+       else
                kfree_skb(skb);
 
        return NETDEV_TX_OK;
@@ -3981,87 +3715,39 @@ static int bond_xmit_activebackup(struct sk_buff *skb, struct net_device *bond_d
 static int bond_xmit_xor(struct sk_buff *skb, struct net_device *bond_dev)
 {
        struct bonding *bond = netdev_priv(bond_dev);
-       struct slave *slave, *start_at;
-       int slave_no;
-       int i;
-       int res = 1;
 
-       slave_no = bond->xmit_hash_policy(skb, bond->slave_cnt);
-
-       bond_for_each_slave(bond, slave, i) {
-               slave_no--;
-               if (slave_no < 0)
-                       break;
-       }
-
-       start_at = slave;
-
-       bond_for_each_slave_from(bond, slave, i, start_at) {
-               if (IS_UP(slave->dev) &&
-                   (slave->link == BOND_LINK_UP) &&
-                   bond_is_active_slave(slave)) {
-                       res = bond_dev_queue_xmit(bond, skb, slave->dev);
-                       break;
-               }
-       }
-
-       if (res) {
-               /* no suitable interface, frame not sent */
-               kfree_skb(skb);
-       }
+       bond_xmit_slave_id(bond, skb,
+                          bond->xmit_hash_policy(skb, bond->slave_cnt));
 
        return NETDEV_TX_OK;
 }
 
-/*
- * in broadcast mode, we send everything to all usable interfaces.
- */
+/* in broadcast mode, we send everything to all usable interfaces. */
 static int bond_xmit_broadcast(struct sk_buff *skb, struct net_device *bond_dev)
 {
        struct bonding *bond = netdev_priv(bond_dev);
-       struct slave *slave, *start_at;
-       struct net_device *tx_dev = NULL;
-       int i;
-       int res = 1;
-
-       read_lock(&bond->curr_slave_lock);
-       start_at = bond->curr_active_slave;
-       read_unlock(&bond->curr_slave_lock);
-
-       if (!start_at)
-               goto out;
+       struct slave *slave = NULL;
 
-       bond_for_each_slave_from(bond, slave, i, start_at) {
-               if (IS_UP(slave->dev) &&
-                   (slave->link == BOND_LINK_UP) &&
-                   bond_is_active_slave(slave)) {
-                       if (tx_dev) {
-                               struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
-                               if (!skb2) {
-                                       pr_err("%s: Error: bond_xmit_broadcast(): skb_clone() failed\n",
-                                              bond_dev->name);
-                                       continue;
-                               }
+       bond_for_each_slave_rcu(bond, slave) {
+               if (bond_is_last_slave(bond, slave))
+                       break;
+               if (IS_UP(slave->dev) && slave->link == BOND_LINK_UP) {
+                       struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
 
-                               res = bond_dev_queue_xmit(bond, skb2, tx_dev);
-                               if (res) {
-                                       kfree_skb(skb2);
-                                       continue;
-                               }
+                       if (!skb2) {
+                               pr_err("%s: Error: bond_xmit_broadcast(): skb_clone() failed\n",
+                                      bond_dev->name);
+                               continue;
                        }
-                       tx_dev = slave->dev;
+                       /* bond_dev_queue_xmit always returns 0 */
+                       bond_dev_queue_xmit(bond, skb2, slave->dev);
                }
        }
-
-       if (tx_dev)
-               res = bond_dev_queue_xmit(bond, skb, tx_dev);
-
-out:
-       if (res)
-               /* no suitable interface, frame not sent */
+       if (slave && IS_UP(slave->dev) && slave->link == BOND_LINK_UP)
+               bond_dev_queue_xmit(bond, skb, slave->dev);
+       else
                kfree_skb(skb);
 
-       /* frame sent to all suitable interfaces */
        return NETDEV_TX_OK;
 }
 
@@ -4089,15 +3775,15 @@ static void bond_set_xmit_hash_policy(struct bonding *bond)
 static inline int bond_slave_override(struct bonding *bond,
                                      struct sk_buff *skb)
 {
-       int i, res = 1;
        struct slave *slave = NULL;
        struct slave *check_slave;
+       int res = 1;
 
        if (!skb->queue_mapping)
                return 1;
 
        /* Find out if any slaves have the same mapping as this skb. */
-       bond_for_each_slave(bond, check_slave, i) {
+       bond_for_each_slave_rcu(bond, check_slave) {
                if (check_slave->queue_id == skb->queue_mapping) {
                        slave = check_slave;
                        break;
@@ -4182,14 +3868,12 @@ static netdev_tx_t bond_start_xmit(struct sk_buff *skb, struct net_device *dev)
        if (is_netpoll_tx_blocked(dev))
                return NETDEV_TX_BUSY;
 
-       read_lock(&bond->lock);
-
-       if (bond->slave_cnt)
+       rcu_read_lock();
+       if (!list_empty(&bond->slave_list))
                ret = __bond_start_xmit(skb, dev);
        else
                kfree_skb(skb);
-
-       read_unlock(&bond->lock);
+       rcu_read_unlock();
 
        return ret;
 }
@@ -4230,9 +3914,8 @@ static int bond_ethtool_get_settings(struct net_device *bond_dev,
                                     struct ethtool_cmd *ecmd)
 {
        struct bonding *bond = netdev_priv(bond_dev);
-       struct slave *slave;
-       int i;
        unsigned long speed = 0;
+       struct slave *slave;
 
        ecmd->duplex = DUPLEX_UNKNOWN;
        ecmd->port = PORT_OTHER;
@@ -4243,7 +3926,7 @@ static int bond_ethtool_get_settings(struct net_device *bond_dev,
         * this is an accurate maximum.
         */
        read_lock(&bond->lock);
-       bond_for_each_slave(bond, slave, i) {
+       bond_for_each_slave(bond, slave) {
                if (SLAVE_IS_OK(slave)) {
                        if (slave->speed != SPEED_UNKNOWN)
                                speed += slave->speed;
@@ -4254,6 +3937,7 @@ static int bond_ethtool_get_settings(struct net_device *bond_dev,
        }
        ethtool_cmd_speed_set(ecmd, speed ? : SPEED_UNKNOWN);
        read_unlock(&bond->lock);
+
        return 0;
 }
 
@@ -4317,12 +4001,11 @@ static void bond_setup(struct net_device *bond_dev)
        /* initialize rwlocks */
        rwlock_init(&bond->lock);
        rwlock_init(&bond->curr_slave_lock);
-
+       INIT_LIST_HEAD(&bond->slave_list);
        bond->params = bonding_defaults;
 
        /* Initialize pointers */
        bond->dev = bond_dev;
-       INIT_LIST_HEAD(&bond->vlan_list);
 
        /* Initialize the device entry points */
        ether_setup(bond_dev);
@@ -4374,23 +4057,18 @@ static void bond_setup(struct net_device *bond_dev)
 static void bond_uninit(struct net_device *bond_dev)
 {
        struct bonding *bond = netdev_priv(bond_dev);
-       struct vlan_entry *vlan, *tmp;
+       struct slave *slave, *tmp_slave;
 
        bond_netpoll_cleanup(bond_dev);
 
        /* Release the bonded slaves */
-       while (bond->first_slave != NULL)
-               __bond_release_one(bond_dev, bond->first_slave->dev, true);
+       list_for_each_entry_safe(slave, tmp_slave, &bond->slave_list, list)
+               __bond_release_one(bond_dev, slave->dev, true);
        pr_info("%s: released all slaves\n", bond_dev->name);
 
        list_del(&bond->bond_list);
 
        bond_debug_unregister(bond);
-
-       list_for_each_entry_safe(vlan, tmp, &bond->vlan_list, vlan_list) {
-               list_del(&vlan->vlan_list);
-               kfree(vlan);
-       }
 }
 
 /*------------------------- Module initialization ---------------------------*/
@@ -4745,6 +4423,7 @@ static int bond_check_params(struct bond_params *params)
        params->all_slaves_active = all_slaves_active;
        params->resend_igmp = resend_igmp;
        params->min_links = min_links;
+       params->lp_interval = BOND_ALB_DEFAULT_LP_INTERVAL;
 
        if (primary) {
                strncpy(params->primary, primary, IFNAMSIZ);