Linux Ethernet Bonding Driver HOWTO
 
-               Latest update: 23 September 2009
+               Latest update: 27 April 2011
 
 Initial release : Thomas Davis <tadavis at lbl.gov>
 Corrections, HA extensions : 2000/10/03-15 :
                chosen.
 
 num_grat_arp
-
-       Specifies the number of gratuitous ARPs to be issued after a
-       failover event.  One gratuitous ARP is issued immediately after
-       the failover, subsequent ARPs are sent at a rate of one per link
-       monitor interval (arp_interval or miimon, whichever is active).
-
-       The valid range is 0 - 255; the default value is 1.  This option
-       affects only the active-backup mode.  This option was added for
-       bonding version 3.3.0.
-
 num_unsol_na
 
-       Specifies the number of unsolicited IPv6 Neighbor Advertisements
-       to be issued after a failover event.  One unsolicited NA is issued
-       immediately after the failover.
-
-       The valid range is 0 - 255; the default value is 1.  This option
-       affects only the active-backup mode.  This option was added for
-       bonding version 3.4.0.
+       Specify the number of peer notifications (gratuitous ARPs and
+       unsolicited IPv6 Neighbor Advertisements) to be issued after a
+       failover event.  As soon as the link is up on the new slave
+       (possibly immediately) a peer notification is sent on the
+       bonding device and each VLAN sub-device.  This is repeated at
+       each link monitor interval (arp_interval or miimon, whichever
+       is active) if the number is greater than 1.
+
+       The valid range is 0 - 255; the default value is 1.  These options
+       affect only the active-backup mode.  These options were added for
+       bonding versions 3.3.0 and 3.4.0 respectively.
+
+       From Linux 2.6.40 and bonding version 3.7.1, these notifications
+       are generated by the ipv4 and ipv6 code and the numbers of
+       repetitions cannot be set independently.
 
 primary
 
 
 
 static int max_bonds   = BOND_DEFAULT_MAX_BONDS;
 static int tx_queues   = BOND_DEFAULT_TX_QUEUES;
+static int num_peer_notif = 1;
 static int miimon      = BOND_LINK_MON_INTERV;
 static int updelay;
 static int downdelay;
 MODULE_PARM_DESC(max_bonds, "Max number of bonded devices");
 module_param(tx_queues, int, 0);
 MODULE_PARM_DESC(tx_queues, "Max number of transmit queues (default = 16)");
+module_param_named(num_grat_arp, num_peer_notif, int, 0644);
+MODULE_PARM_DESC(num_grat_arp, "Number of peer notifications to send on failover event (alias of num_unsol_na)");
+module_param_named(num_unsol_na, num_peer_notif, int, 0644);
+MODULE_PARM_DESC(num_unsol_na, "Number of peer notifications to send on failover event (alias of num_grat_arp)");
 module_param(miimon, int, 0);
 MODULE_PARM_DESC(miimon, "Link check interval in milliseconds");
 module_param(updelay, int, 0);
        return bestslave;
 }
 
+static bool bond_should_notify_peers(struct bonding *bond)
+{
+       struct slave *slave = bond->curr_active_slave;
+
+       pr_debug("bond_should_notify_peers: bond %s slave %s\n",
+                bond->dev->name, slave ? slave->dev->name : "NULL");
+
+       if (!slave || !bond->send_peer_notif ||
+           test_bit(__LINK_STATE_LINKWATCH_PENDING, &slave->dev->state))
+               return false;
+
+       bond->send_peer_notif--;
+       return true;
+}
+
 /**
  * change_active_interface - change the active slave into the specified one
  * @bond: our bonding struct
                        bond_set_slave_inactive_flags(old_active);
 
                if (new_active) {
+                       bool should_notify_peers = false;
+
                        bond_set_slave_active_flags(new_active);
 
                        if (bond->params.fail_over_mac)
                                bond_do_fail_over_mac(bond, new_active,
                                                      old_active);
 
+                       if (netif_running(bond->dev)) {
+                               bond->send_peer_notif =
+                                       bond->params.num_peer_notif;
+                               should_notify_peers =
+                                       bond_should_notify_peers(bond);
+                       }
+
                        write_unlock_bh(&bond->curr_slave_lock);
                        read_unlock(&bond->lock);
 
                        netdev_bonding_change(bond->dev, NETDEV_BONDING_FAILOVER);
+                       if (should_notify_peers)
+                               netdev_bonding_change(bond->dev,
+                                                     NETDEV_NOTIFY_PEERS);
 
                        read_lock(&bond->lock);
                        write_lock_bh(&bond->curr_slave_lock);
 {
        struct bonding *bond = container_of(work, struct bonding,
                                            mii_work.work);
+       bool should_notify_peers = false;
 
        read_lock(&bond->lock);
        if (bond->kill_timers)
        if (bond->slave_cnt == 0)
                goto re_arm;
 
+       should_notify_peers = bond_should_notify_peers(bond);
+
        if (bond_miimon_inspect(bond)) {
                read_unlock(&bond->lock);
                rtnl_lock();
                                   msecs_to_jiffies(bond->params.miimon));
 out:
        read_unlock(&bond->lock);
+
+       if (should_notify_peers) {
+               rtnl_lock();
+               netdev_bonding_change(bond->dev, NETDEV_NOTIFY_PEERS);
+               rtnl_unlock();
+       }
 }
 
 static __be32 bond_glean_dev_ip(struct net_device *dev)
 {
        struct bonding *bond = container_of(work, struct bonding,
                                            arp_work.work);
+       bool should_notify_peers = false;
        int delta_in_ticks;
 
        read_lock(&bond->lock);
        if (bond->slave_cnt == 0)
                goto re_arm;
 
+       should_notify_peers = bond_should_notify_peers(bond);
+
        if (bond_ab_arp_inspect(bond, delta_in_ticks)) {
                read_unlock(&bond->lock);
                rtnl_lock();
                queue_delayed_work(bond->wq, &bond->arp_work, delta_in_ticks);
 out:
        read_unlock(&bond->lock);
+
+       if (should_notify_peers) {
+               rtnl_lock();
+               netdev_bonding_change(bond->dev, NETDEV_NOTIFY_PEERS);
+               rtnl_unlock();
+       }
 }
 
 /*-------------------------- netdev event handling --------------------------*/
 
        write_lock_bh(&bond->lock);
 
+       bond->send_peer_notif = 0;
+
        /* signal timers not to re-arm */
        bond->kill_timers = 1;
 
                use_carrier = 1;
        }
 
+       if (num_peer_notif < 0 || num_peer_notif > 255) {
+               pr_warning("Warning: num_grat_arp/num_unsol_na (%d) not in range 0-255 so it was reset to 1\n",
+                          num_peer_notif);
+               num_peer_notif = 1;
+       }
+
        /* reset values for 802.3ad */
        if (bond_mode == BOND_MODE_8023AD) {
                if (!miimon) {
        params->mode = bond_mode;
        params->xmit_policy = xmit_hashtype;
        params->miimon = miimon;
+       params->num_peer_notif = num_peer_notif;
        params->arp_interval = arp_interval;
        params->arp_validate = arp_validate_value;
        params->updelay = updelay;
 
 static DEVICE_ATTR(ad_select, S_IRUGO | S_IWUSR,
                   bonding_show_ad_select, bonding_store_ad_select);
 
+/*
+ * Show and set the number of peer notifications to send after a failover event.
+ */
+static ssize_t bonding_show_num_peer_notif(struct device *d,
+                                          struct device_attribute *attr,
+                                          char *buf)
+{
+       struct bonding *bond = to_bond(d);
+       return sprintf(buf, "%d\n", bond->params.num_peer_notif);
+}
+
+static ssize_t bonding_store_num_peer_notif(struct device *d,
+                                           struct device_attribute *attr,
+                                           const char *buf, size_t count)
+{
+       struct bonding *bond = to_bond(d);
+       int err = kstrtou8(buf, 10, &bond->params.num_peer_notif);
+       return err ? err : count;
+}
+static DEVICE_ATTR(num_grat_arp, S_IRUGO | S_IWUSR,
+                  bonding_show_num_peer_notif, bonding_store_num_peer_notif);
+static DEVICE_ATTR(num_unsol_na, S_IRUGO | S_IWUSR,
+                  bonding_show_num_peer_notif, bonding_store_num_peer_notif);
+
 /*
  * Show and set the MII monitor interval.  There are two tricky bits
  * here.  First, if MII monitoring is activated, then we must disable
        &dev_attr_lacp_rate.attr,
        &dev_attr_ad_select.attr,
        &dev_attr_xmit_hash_policy.attr,
+       &dev_attr_num_grat_arp.attr,
+       &dev_attr_num_unsol_na.attr,
        &dev_attr_miimon.attr,
        &dev_attr_primary.attr,
        &dev_attr_primary_reselect.attr,