[PATCH] bonding: support carrier state for master
[kernel/kernel-generic.git] / drivers / net / bonding / bond_main.c
index f13a539..55d2367 100644 (file)
@@ -559,6 +559,42 @@ out:
 /*------------------------------- Link status -------------------------------*/
 
 /*
+ * Set the carrier state for the master according to the state of its
+ * slaves.  If any slaves are up, the master is up.  In 802.3ad mode,
+ * do special 802.3ad magic.
+ *
+ * Returns zero if carrier state does not change, nonzero if it does.
+ */
+static int bond_set_carrier(struct bonding *bond)
+{
+       struct slave *slave;
+       int i;
+
+       if (bond->slave_cnt == 0)
+               goto down;
+
+       if (bond->params.mode == BOND_MODE_8023AD)
+               return bond_3ad_set_carrier(bond);
+
+       bond_for_each_slave(bond, slave, i) {
+               if (slave->link == BOND_LINK_UP) {
+                       if (!netif_carrier_ok(bond->dev)) {
+                               netif_carrier_on(bond->dev);
+                               return 1;
+                       }
+                       return 0;
+               }
+       }
+
+down:
+       if (netif_carrier_ok(bond->dev)) {
+               netif_carrier_off(bond->dev);
+               return 1;
+       }
+       return 0;
+}
+
+/*
  * Get link speed and duplex from the slave's base driver
  * using ethtool. If for some reason the call fails or the
  * values are invalid, fake speed and duplex to 100/Full
@@ -1074,10 +1110,24 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
 void bond_select_active_slave(struct bonding *bond)
 {
        struct slave *best_slave;
+       int rv;
 
        best_slave = bond_find_best_slave(bond);
        if (best_slave != bond->curr_active_slave) {
                bond_change_active_slave(bond, best_slave);
+               rv = bond_set_carrier(bond);
+               if (!rv)
+                       return;
+
+               if (netif_carrier_ok(bond->dev)) {
+                       printk(KERN_INFO DRV_NAME
+                              ": %s: first active interface up!\n",
+                              bond->dev->name);
+               } else {
+                       printk(KERN_INFO DRV_NAME ": %s: "
+                              "now running without any active interface !\n",
+                              bond->dev->name);
+               }
        }
 }
 
@@ -1458,10 +1508,14 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
                if (((!bond->curr_active_slave) ||
                     (bond->curr_active_slave->dev->priv_flags & IFF_SLAVE_INACTIVE)) &&
                    (new_slave->link != BOND_LINK_DOWN)) {
-                       dprintk("This is the first active slave\n");
                        /* first slave or no active slave yet, and this link
                           is OK, so make this interface the active one */
                        bond_change_active_slave(bond, new_slave);
+                       printk(KERN_INFO DRV_NAME
+                              ": %s: first active interface up!\n",
+                              bond->dev->name);
+                       netif_carrier_on(bond->dev);
+
                } else {
                        dprintk("This is just a backup slave\n");
                        bond_set_slave_inactive_flags(new_slave);
@@ -1517,6 +1571,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
                break;
        } /* switch(bond_mode) */
 
+       bond_set_carrier(bond);
+
        write_unlock_bh(&bond->lock);
 
        res = bond_create_slave_symlinks(bond_dev, slave_dev);
@@ -1656,18 +1712,12 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
                bond_alb_deinit_slave(bond, slave);
        }
 
-       if (oldcurrent == slave) {
+       if (oldcurrent == slave)
                bond_select_active_slave(bond);
 
-               if (!bond->curr_active_slave) {
-                       printk(KERN_INFO DRV_NAME
-                              ": %s: now running without any active "
-                              "interface !\n",
-                              bond_dev->name);
-               }
-       }
-
        if (bond->slave_cnt == 0) {
+               bond_set_carrier(bond);
+
                /* if the last slave was removed, zero the mac address
                 * of the master so it will be set by the application
                 * to the mac address of the first slave
@@ -1751,6 +1801,8 @@ static int bond_release_all(struct net_device *bond_dev)
 
        write_lock_bh(&bond->lock);
 
+       netif_carrier_off(bond_dev);
+
        if (bond->slave_cnt == 0) {
                goto out;
        }
@@ -2187,15 +2239,9 @@ void bond_mii_monitor(struct net_device *bond_dev)
 
                bond_select_active_slave(bond);
 
-               if (oldcurrent && !bond->curr_active_slave) {
-                       printk(KERN_INFO DRV_NAME
-                              ": %s: now running without any active "
-                              "interface !\n",
-                              bond_dev->name);
-               }
-
                write_unlock(&bond->curr_slave_lock);
-       }
+       } else
+               bond_set_carrier(bond);
 
 re_arm:
        if (bond->params.miimon) {
@@ -2499,13 +2545,6 @@ void bond_loadbalance_arp_mon(struct net_device *bond_dev)
 
                bond_select_active_slave(bond);
 
-               if (oldcurrent && !bond->curr_active_slave) {
-                       printk(KERN_INFO DRV_NAME
-                              ": %s: now running without any active "
-                              "interface !\n",
-                              bond_dev->name);
-               }
-
                write_unlock(&bond->curr_slave_lock);
        }
 
@@ -2579,12 +2618,15 @@ void bond_activebackup_arp_mon(struct net_device *bond_dev)
                                        bond->current_arp_slave = NULL;
                                }
 
+                               bond_set_carrier(bond);
+
                                if (slave == bond->curr_active_slave) {
                                        printk(KERN_INFO DRV_NAME
                                               ": %s: %s is up and now the "
                                               "active interface\n",
                                               bond_dev->name,
                                               slave->dev->name);
+                                       netif_carrier_on(bond->dev);
                                } else {
                                        printk(KERN_INFO DRV_NAME
                                               ": %s: backup interface %s is "
@@ -2844,7 +2886,8 @@ static void bond_info_show_master(struct seq_file *seq)
                           (curr) ? curr->dev->name : "None");
        }
 
-       seq_printf(seq, "MII Status: %s\n", (curr) ? "up" : "down");
+       seq_printf(seq, "MII Status: %s\n", netif_carrier_ok(bond->dev) ?
+                  "up" : "down");
        seq_printf(seq, "MII Polling Interval (ms): %d\n", bond->params.miimon);
        seq_printf(seq, "Up Delay (ms): %d\n",
                   bond->params.updelay * bond->params.miimon);
@@ -4531,6 +4574,8 @@ int bond_create(char *name, struct bond_params *params, struct bonding **newbond
        if (newbond)
                *newbond = bond_dev->priv;
 
+       netif_carrier_off(bond_dev);
+
        rtnl_unlock(); /* allows sysfs registration of net device */
        res = bond_create_sysfs_entry(bond_dev->priv);
        goto done;