bonding: Rework / fix multiple gratuitous ARP support
[safe/jmp/linux-2.6] / drivers / net / bonding / bond_main.c
index 925402b..3b6d66a 100644 (file)
@@ -1195,14 +1195,7 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
                                                      old_active);
 
                        bond->send_grat_arp = bond->params.num_grat_arp;
-                       if (!test_bit(__LINK_STATE_LINKWATCH_PENDING,
-                                       &bond->curr_active_slave->dev->state)) {
-                               bond_send_gratuitous_arp(bond);
-                               bond->send_grat_arp--;
-                       } else {
-                               dprintk("delaying gratuitous arp on %s\n",
-                                       bond->curr_active_slave->dev->name);
-                       }
+                       bond_send_gratuitous_arp(bond);
 
                        write_unlock_bh(&bond->curr_slave_lock);
                        read_unlock(&bond->lock);
@@ -2241,17 +2234,6 @@ static int __bond_mii_monitor(struct bonding *bond, int have_locks)
         * program could monitor the link itself if needed.
         */
 
-       if (bond->send_grat_arp) {
-               if (bond->curr_active_slave && test_bit(__LINK_STATE_LINKWATCH_PENDING,
-                               &bond->curr_active_slave->dev->state))
-                       dprintk("Needs to send gratuitous arp but not yet\n");
-               else {
-                       dprintk("sending delayed gratuitous arp on on %s\n",
-                               bond->curr_active_slave->dev->name);
-                       bond_send_gratuitous_arp(bond);
-                       bond->send_grat_arp--;
-               }
-       }
        read_lock(&bond->curr_slave_lock);
        oldcurrent = bond->curr_active_slave;
        read_unlock(&bond->curr_slave_lock);
@@ -2492,6 +2474,13 @@ void bond_mii_monitor(struct work_struct *work)
                read_unlock(&bond->lock);
                return;
        }
+
+       if (bond->send_grat_arp) {
+               read_lock(&bond->curr_slave_lock);
+               bond_send_gratuitous_arp(bond);
+               read_unlock(&bond->curr_slave_lock);
+       }
+
        if (__bond_mii_monitor(bond, 0)) {
                read_unlock(&bond->lock);
                rtnl_lock();
@@ -2657,6 +2646,8 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
 /*
  * Kick out a gratuitous ARP for an IP on the bonding master plus one
  * for each VLAN above us.
+ *
+ * Caller must hold curr_slave_lock for read or better
  */
 static void bond_send_gratuitous_arp(struct bonding *bond)
 {
@@ -2666,9 +2657,13 @@ static void bond_send_gratuitous_arp(struct bonding *bond)
 
        dprintk("bond_send_grat_arp: bond %s slave %s\n", bond->dev->name,
                                slave ? slave->dev->name : "NULL");
-       if (!slave)
+
+       if (!slave || !bond->send_grat_arp ||
+           test_bit(__LINK_STATE_LINKWATCH_PENDING, &slave->dev->state))
                return;
 
+       bond->send_grat_arp--;
+
        if (bond->master_ip) {
                bond_arp_send(slave->dev, ARPOP_REPLY, bond->master_ip,
                                bond->master_ip, 0);
@@ -3172,6 +3167,12 @@ void bond_activebackup_arp_mon(struct work_struct *work)
        if (bond->slave_cnt == 0)
                goto re_arm;
 
+       if (bond->send_grat_arp) {
+               read_lock(&bond->curr_slave_lock);
+               bond_send_gratuitous_arp(bond);
+               read_unlock(&bond->curr_slave_lock);
+       }
+
        if (bond_ab_arp_inspect(bond, delta_in_ticks)) {
                read_unlock(&bond->lock);
                rtnl_lock();
@@ -3846,6 +3847,7 @@ static int bond_close(struct net_device *bond_dev)
 
        write_lock_bh(&bond->lock);
 
+       bond->send_grat_arp = 0;
 
        /* signal timers not to re-arm */
        bond->kill_timers = 1;