ipv4, ipv6, bonding: Restore control over number of peer notifications
authorBen Hutchings <bhutchings@solarflare.com>
Tue, 26 Apr 2011 15:25:52 +0000 (15:25 +0000)
committerDavid S. Miller <davem@davemloft.net>
Fri, 29 Apr 2011 19:44:11 +0000 (12:44 -0700)
For backward compatibility, we should retain the module parameters and
sysfs attributes to control the number of peer notifications
(gratuitous ARPs and unsolicited NAs) sent after bonding failover.
Also, it is possible for failover to take place even though the new
active slave does not have link up, and in that case the peer
notification should be deferred until it does.

Change ipv4 and ipv6 so they do not automatically send peer
notifications on bonding failover.

Change the bonding driver to send separate NETDEV_NOTIFY_PEERS
notifications when the link is up, as many times as requested.  Since
it does not directly control which protocols send notifications, make
num_grat_arp and num_unsol_na aliases for a single parameter.  Bump
the bonding version number and update its documentation.

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
Signed-off-by: Jay Vosburgh <fubar@us.ibm.com>
Acked-by: Brian Haley <brian.haley@hp.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Documentation/networking/bonding.txt
drivers/net/bonding/bond_main.c
drivers/net/bonding/bond_sysfs.c
drivers/net/bonding/bonding.h
net/ipv4/devinet.c
net/ipv6/ndisc.c

index e27202bb8d752dd72dead86953976762b78e34be..1f45bd887d65615621ac5443875dc81097166f10 100644 (file)
@@ -1,7 +1,7 @@
 
                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 :
@@ -585,25 +585,23 @@ mode
                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
 
index 66d9dc6e5cacd0b5197234a2ea7cd426252661a3..22bd03bd1d3598a90b18797928fd4cf1531b3267 100644 (file)
@@ -89,6 +89,7 @@
 
 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;
@@ -111,6 +112,10 @@ module_param(max_bonds, int, 0);
 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);
@@ -1082,6 +1087,21 @@ static struct slave *bond_find_best_slave(struct bonding *bond)
        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
@@ -1149,16 +1169,28 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
                        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);
@@ -2556,6 +2588,7 @@ void bond_mii_monitor(struct work_struct *work)
 {
        struct bonding *bond = container_of(work, struct bonding,
                                            mii_work.work);
+       bool should_notify_peers = false;
 
        read_lock(&bond->lock);
        if (bond->kill_timers)
@@ -2564,6 +2597,8 @@ void bond_mii_monitor(struct work_struct *work)
        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();
@@ -2582,6 +2617,12 @@ re_arm:
                                   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)
@@ -3154,6 +3195,7 @@ void bond_activebackup_arp_mon(struct work_struct *work)
 {
        struct bonding *bond = container_of(work, struct bonding,
                                            arp_work.work);
+       bool should_notify_peers = false;
        int delta_in_ticks;
 
        read_lock(&bond->lock);
@@ -3166,6 +3208,8 @@ void bond_activebackup_arp_mon(struct work_struct *work)
        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();
@@ -3185,6 +3229,12 @@ re_arm:
                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 --------------------------*/
@@ -3494,6 +3544,8 @@ static int bond_close(struct net_device *bond_dev)
 
        write_lock_bh(&bond->lock);
 
+       bond->send_peer_notif = 0;
+
        /* signal timers not to re-arm */
        bond->kill_timers = 1;
 
@@ -4571,6 +4623,12 @@ static int bond_check_params(struct bond_params *params)
                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) {
@@ -4760,6 +4818,7 @@ static int bond_check_params(struct bond_params *params)
        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;
index 935406aa5f0c3a83d5b92917af0543acb8dc44bf..4059bfc73dbf531d3e7c7df946c6615b611c51a5 100644 (file)
@@ -868,6 +868,30 @@ out:
 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
@@ -1566,6 +1590,8 @@ static struct attribute *per_bond_attrs[] = {
        &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,
index 85fb8220e283ed37c5d002017b129b95da9c9543..d08362e1a0dd124d1d1afe375583170d4c65db49 100644 (file)
@@ -24,8 +24,8 @@
 #include "bond_3ad.h"
 #include "bond_alb.h"
 
-#define DRV_VERSION    "3.7.0"
-#define DRV_RELDATE    "June 2, 2010"
+#define DRV_VERSION    "3.7.1"
+#define DRV_RELDATE    "April 27, 2011"
 #define DRV_NAME       "bonding"
 #define DRV_DESCRIPTION        "Ethernet Channel Bonding Driver"
 
@@ -149,6 +149,7 @@ struct bond_params {
        int mode;
        int xmit_policy;
        int miimon;
+       u8 num_peer_notif;
        int arp_interval;
        int arp_validate;
        int use_carrier;
@@ -231,6 +232,7 @@ struct bonding {
        rwlock_t lock;
        rwlock_t curr_slave_lock;
        s8       kill_timers;
+       u8       send_peer_notif;
        s8       setup_by_slave;
        s8       igmp_retrans;
 #ifdef CONFIG_PROC_FS
index acf553f95b5b0ff61e7eb678a9016e20781554e5..5345b0bee6df816858c1424d0ccb50988d133aa2 100644 (file)
@@ -1203,7 +1203,6 @@ static int inetdev_event(struct notifier_block *this, unsigned long event,
                        break;
                /* fall through */
        case NETDEV_NOTIFY_PEERS:
-       case NETDEV_BONDING_FAILOVER:
                /* Send gratuitous ARP to notify of link change */
                inetdev_send_gratuitous_arp(dev, in_dev);
                break;
index 69aacd18e066299085e00455253db887f3f31cee..7596f071d3088cd86643ade87203b39eb42c6552 100644 (file)
@@ -1747,7 +1747,6 @@ static int ndisc_netdev_event(struct notifier_block *this, unsigned long event,
                fib6_run_gc(~0UL, net);
                break;
        case NETDEV_NOTIFY_PEERS:
-       case NETDEV_BONDING_FAILOVER:
                ndisc_send_unsol_na(dev);
                break;
        default: