bonding: remove useless assignment
[pandora-kernel.git] / drivers / net / bonding / bond_main.c
index aa1be1f..ef6af1c 100644 (file)
@@ -94,6 +94,7 @@ static int downdelay;
 static int use_carrier = 1;
 static char *mode;
 static char *primary;
+static char *primary_reselect;
 static char *lacp_rate;
 static char *ad_select;
 static char *xmit_hash_policy;
@@ -126,6 +127,14 @@ MODULE_PARM_DESC(mode, "Mode of operation : 0 for balance-rr, "
                       "6 for balance-alb");
 module_param(primary, charp, 0);
 MODULE_PARM_DESC(primary, "Primary network device to use");
+module_param(primary_reselect, charp, 0);
+MODULE_PARM_DESC(primary_reselect, "Reselect primary slave "
+                                  "once it comes up; "
+                                  "0 for always (default), "
+                                  "1 for only if speed of primary is "
+                                  "better, "
+                                  "2 for only on active slave "
+                                  "failure");
 module_param(lacp_rate, charp, 0);
 MODULE_PARM_DESC(lacp_rate, "LACPDU tx rate to request from 802.3ad partner "
                            "(slow/fast)");
@@ -200,6 +209,13 @@ const struct bond_parm_tbl fail_over_mac_tbl[] = {
 {      NULL,                   -1},
 };
 
+const struct bond_parm_tbl pri_reselect_tbl[] = {
+{      "always",               BOND_PRI_RESELECT_ALWAYS},
+{      "better",               BOND_PRI_RESELECT_BETTER},
+{      "failure",              BOND_PRI_RESELECT_FAILURE},
+{      NULL,                   -1},
+};
+
 struct bond_parm_tbl ad_select_tbl[] = {
 {      "stable",       BOND_AD_STABLE},
 {      "bandwidth",    BOND_AD_BANDWIDTH},
@@ -695,6 +711,9 @@ static int bond_check_dev_link(struct bonding *bond,
        struct ifreq ifr;
        struct mii_ioctl_data *mii;
 
+       if (!reporting && !netif_running(slave_dev))
+               return 0;
+
        if (bond->params.use_carrier)
                return netif_carrier_ok(slave_dev) ? BMSR_LSTATUS : 0;
 
@@ -1067,6 +1086,25 @@ out:
 
 }
 
+static bool bond_should_change_active(struct bonding *bond)
+{
+       struct slave *prim = bond->primary_slave;
+       struct slave *curr = bond->curr_active_slave;
+
+       if (!prim || !curr || curr->link != BOND_LINK_UP)
+               return true;
+       if (bond->force_primary) {
+               bond->force_primary = false;
+               return true;
+       }
+       if (bond->params.primary_reselect == BOND_PRI_RESELECT_BETTER &&
+           (prim->speed < curr->speed ||
+            (prim->speed == curr->speed && prim->duplex <= curr->duplex)))
+               return false;
+       if (bond->params.primary_reselect == BOND_PRI_RESELECT_FAILURE)
+               return false;
+       return true;
+}
 
 /**
  * find_best_interface - select the best available slave to be the active one
@@ -1081,7 +1119,7 @@ static struct slave *bond_find_best_slave(struct bonding *bond)
        int mintime = bond->params.updelay;
        int i;
 
-       new_active = old_active = bond->curr_active_slave;
+       new_active = bond->curr_active_slave;
 
        if (!new_active) { /* there were no active slaves left */
                if (bond->slave_cnt > 0)   /* found one slave */
@@ -1090,15 +1128,9 @@ static struct slave *bond_find_best_slave(struct bonding *bond)
                        return NULL; /* still no slave, return NULL */
        }
 
-       /*
-        * first try the primary link; if arping, a link must tx/rx
-        * traffic before it can be considered the curr_active_slave.
-        * also, we would skip slaves between the curr_active_slave
-        * and primary_slave that may be up and able to arp
-        */
        if ((bond->primary_slave) &&
-           (!bond->params.arp_interval) &&
-           (IS_UP(bond->primary_slave->dev))) {
+           bond->primary_slave->link == BOND_LINK_UP &&
+           bond_should_change_active(bond)) {
                new_active = bond->primary_slave;
        }
 
@@ -1106,15 +1138,14 @@ static struct slave *bond_find_best_slave(struct bonding *bond)
        old_active = new_active;
 
        bond_for_each_slave_from(bond, new_active, i, old_active) {
-               if (IS_UP(new_active->dev)) {
-                       if (new_active->link == BOND_LINK_UP) {
-                               return new_active;
-                       } else if (new_active->link == BOND_LINK_BACK) {
-                               /* link up, but waiting for stabilization */
-                               if (new_active->delay < mintime) {
-                                       mintime = new_active->delay;
-                                       bestslave = new_active;
-                               }
+               if (new_active->link == BOND_LINK_UP) {
+                       return new_active;
+               } else if (new_active->link == BOND_LINK_BACK &&
+                          IS_UP(new_active->dev)) {
+                       /* link up, but waiting for stabilization */
+                       if (new_active->delay < mintime) {
+                               mintime = new_active->delay;
+                               bestslave = new_active;
                        }
                }
        }
@@ -1208,7 +1239,7 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
                        write_unlock_bh(&bond->curr_slave_lock);
                        read_unlock(&bond->lock);
 
-                       netdev_bonding_change(bond->dev);
+                       netdev_bonding_change(bond->dev, NETDEV_BONDING_FAILOVER);
 
                        read_lock(&bond->lock);
                        write_lock_bh(&bond->curr_slave_lock);
@@ -1331,6 +1362,7 @@ static int bond_compute_features(struct bonding *bond)
        struct slave *slave;
        struct net_device *bond_dev = bond->dev;
        unsigned long features = bond_dev->features;
+       unsigned long vlan_features = 0;
        unsigned short max_hard_header_len = max((u16)ETH_HLEN,
                                                bond_dev->hard_header_len);
        int i;
@@ -1343,10 +1375,14 @@ static int bond_compute_features(struct bonding *bond)
 
        features &= ~NETIF_F_ONE_FOR_ALL;
 
+       vlan_features = bond->first_slave->dev->vlan_features;
        bond_for_each_slave(bond, slave, i) {
                features = netdev_increment_features(features,
                                                     slave->dev->features,
                                                     NETIF_F_ONE_FOR_ALL);
+               vlan_features = netdev_increment_features(vlan_features,
+                                                       slave->dev->vlan_features,
+                                                       NETIF_F_ONE_FOR_ALL);
                if (slave->dev->hard_header_len > max_hard_header_len)
                        max_hard_header_len = slave->dev->hard_header_len;
        }
@@ -1354,6 +1390,7 @@ static int bond_compute_features(struct bonding *bond)
 done:
        features |= (bond_dev->features & BOND_VLAN_FEATURES);
        bond_dev->features = netdev_fix_features(features, NULL);
+       bond_dev->vlan_features = netdev_fix_features(vlan_features, NULL);
        bond_dev->hard_header_len = max_hard_header_len;
 
        return 0;
@@ -1460,14 +1497,17 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
         */
        if (bond->slave_cnt == 0) {
                if (bond_dev->type != slave_dev->type) {
-                       dev_close(bond_dev);
                        pr_debug("%s: change device type from %d to %d\n",
                                bond_dev->name, bond_dev->type, slave_dev->type);
+
+                       netdev_bonding_change(bond_dev, NETDEV_BONDING_OLDTYPE);
+
                        if (slave_dev->type != ARPHRD_ETHER)
                                bond_setup_by_slave(bond_dev, slave_dev);
                        else
                                ether_setup(bond_dev);
-                       dev_open(bond_dev);
+
+                       netdev_bonding_change(bond_dev, NETDEV_BONDING_NEWTYPE);
                }
        } else if (bond_dev->type != slave_dev->type) {
                pr_err(DRV_NAME ": %s ether type (%d) is different "
@@ -1674,8 +1714,10 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
 
        if (USES_PRIMARY(bond->params.mode) && bond->params.primary[0]) {
                /* if there is a primary slave, remember it */
-               if (strcmp(bond->params.primary, new_slave->dev->name) == 0)
+               if (strcmp(bond->params.primary, new_slave->dev->name) == 0) {
                        bond->primary_slave = new_slave;
+                       bond->force_primary = true;
+               }
        }
 
        write_lock_bh(&bond->curr_slave_lock);
@@ -1790,7 +1832,6 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
        struct bonding *bond = netdev_priv(bond_dev);
        struct slave *slave, *oldcurrent;
        struct sockaddr addr;
-       int mac_addr_differ;
 
        /* slave is not a slave or master is not master of this slave */
        if (!(slave_dev->flags & IFF_SLAVE) ||
@@ -1814,9 +1855,8 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
        }
 
        if (!bond->params.fail_over_mac) {
-               mac_addr_differ = memcmp(bond_dev->dev_addr, slave->perm_hwaddr,
-                                        ETH_ALEN);
-               if (!mac_addr_differ && (bond->slave_cnt > 1))
+               if (!compare_ether_addr(bond_dev->dev_addr, slave->perm_hwaddr)
+                   && bond->slave_cnt > 1)
                        pr_warning(DRV_NAME
                               ": %s: Warning: the permanent HWaddr of %s - "
                               "%pM - is still in use by %s. "
@@ -2922,18 +2962,6 @@ static int bond_ab_arp_inspect(struct bonding *bond, int delta_in_ticks)
                }
        }
 
-       read_lock(&bond->curr_slave_lock);
-
-       /*
-        * Trigger a commit if the primary option setting has changed.
-        */
-       if (bond->primary_slave &&
-           (bond->primary_slave != bond->curr_active_slave) &&
-           (bond->primary_slave->link == BOND_LINK_UP))
-               commit++;
-
-       read_unlock(&bond->curr_slave_lock);
-
        return commit;
 }
 
@@ -2954,90 +2982,58 @@ static void bond_ab_arp_commit(struct bonding *bond, int delta_in_ticks)
                        continue;
 
                case BOND_LINK_UP:
-                       write_lock_bh(&bond->curr_slave_lock);
-
-                       if (!bond->curr_active_slave &&
-                           time_before_eq(jiffies, dev_trans_start(slave->dev) +
-                                          delta_in_ticks)) {
+                       if ((!bond->curr_active_slave &&
+                            time_before_eq(jiffies,
+                                           dev_trans_start(slave->dev) +
+                                           delta_in_ticks)) ||
+                           bond->curr_active_slave != slave) {
                                slave->link = BOND_LINK_UP;
-                               bond_change_active_slave(bond, slave);
                                bond->current_arp_slave = NULL;
 
                                pr_info(DRV_NAME
-                                      ": %s: %s is up and now the "
-                                      "active interface\n",
-                                      bond->dev->name, slave->dev->name);
-
-                       } else if (bond->curr_active_slave != slave) {
-                               /* this slave has just come up but we
-                                * already have a current slave; this can
-                                * also happen if bond_enslave adds a new
-                                * slave that is up while we are searching
-                                * for a new slave
-                                */
-                               slave->link = BOND_LINK_UP;
-                               bond_set_slave_inactive_flags(slave);
-                               bond->current_arp_slave = NULL;
+                                       ": %s: link status definitely "
+                                       "up for interface %s.\n",
+                                       bond->dev->name, slave->dev->name);
 
-                               pr_info(DRV_NAME
-                                      ": %s: backup interface %s is now up\n",
-                                      bond->dev->name, slave->dev->name);
-                       }
+                               if (!bond->curr_active_slave ||
+                                   (slave == bond->primary_slave))
+                                       goto do_failover;
 
-                       write_unlock_bh(&bond->curr_slave_lock);
+                       }
 
-                       break;
+                       continue;
 
                case BOND_LINK_DOWN:
                        if (slave->link_failure_count < UINT_MAX)
                                slave->link_failure_count++;
 
                        slave->link = BOND_LINK_DOWN;
+                       bond_set_slave_inactive_flags(slave);
 
-                       if (slave == bond->curr_active_slave) {
-                               pr_info(DRV_NAME
-                                      ": %s: link status down for active "
-                                      "interface %s, disabling it\n",
-                                      bond->dev->name, slave->dev->name);
-
-                               bond_set_slave_inactive_flags(slave);
-
-                               write_lock_bh(&bond->curr_slave_lock);
-
-                               bond_select_active_slave(bond);
-                               if (bond->curr_active_slave)
-                                       bond->curr_active_slave->jiffies =
-                                               jiffies;
-
-                               write_unlock_bh(&bond->curr_slave_lock);
+                       pr_info(DRV_NAME
+                               ": %s: link status definitely down for "
+                               "interface %s, disabling it\n",
+                               bond->dev->name, slave->dev->name);
 
+                       if (slave == bond->curr_active_slave) {
                                bond->current_arp_slave = NULL;
-
-                       } else if (slave->state == BOND_STATE_BACKUP) {
-                               pr_info(DRV_NAME
-                                      ": %s: backup interface %s is now down\n",
-                                      bond->dev->name, slave->dev->name);
-
-                               bond_set_slave_inactive_flags(slave);
+                               goto do_failover;
                        }
-                       break;
+
+                       continue;
 
                default:
                        pr_err(DRV_NAME
                               ": %s: impossible: new_link %d on slave %s\n",
                               bond->dev->name, slave->new_link,
                               slave->dev->name);
+                       continue;
                }
-       }
 
-       /*
-        * No race with changes to primary via sysfs, as we hold rtnl.
-        */
-       if (bond->primary_slave &&
-           (bond->primary_slave != bond->curr_active_slave) &&
-           (bond->primary_slave->link == BOND_LINK_UP)) {
+do_failover:
+               ASSERT_RTNL();
                write_lock_bh(&bond->curr_slave_lock);
-               bond_change_active_slave(bond, bond->primary_slave);
+               bond_select_active_slave(bond);
                write_unlock_bh(&bond->curr_slave_lock);
        }
 
@@ -3243,11 +3239,14 @@ static void bond_info_show_master(struct seq_file *seq)
        }
 
        if (USES_PRIMARY(bond->params.mode)) {
-               seq_printf(seq, "Primary Slave: %s\n",
+               seq_printf(seq, "Primary Slave: %s",
                           (bond->primary_slave) ?
                           bond->primary_slave->dev->name : "None");
+               if (bond->primary_slave)
+                       seq_printf(seq, " (primary_reselect %s)",
+                  pri_reselect_tbl[bond->params.primary_reselect].modename);
 
-               seq_printf(seq, "Currently Active Slave: %s\n",
+               seq_printf(seq, "\nCurrently Active Slave: %s\n",
                           (curr) ? curr->dev->name : "None");
        }
 
@@ -4285,7 +4284,7 @@ out:
                dev_kfree_skb(skb);
        }
        read_unlock(&bond->lock);
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 
@@ -4316,7 +4315,7 @@ out:
 
        read_unlock(&bond->curr_slave_lock);
        read_unlock(&bond->lock);
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /*
@@ -4362,7 +4361,7 @@ out:
                dev_kfree_skb(skb);
        }
        read_unlock(&bond->lock);
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /*
@@ -4422,7 +4421,7 @@ out:
 
        /* frame sent to all suitable interfaces */
        read_unlock(&bond->lock);
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /*------------------------- Device initialization ---------------------------*/
@@ -4443,7 +4442,7 @@ static void bond_set_xmit_hash_policy(struct bonding *bond)
        }
 }
 
-static int bond_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t bond_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        const struct bonding *bond = netdev_priv(dev);
 
@@ -4688,7 +4687,7 @@ int bond_parse_parm(const char *buf, const struct bond_parm_tbl *tbl)
 
 static int bond_check_params(struct bond_params *params)
 {
-       int arp_validate_value, fail_over_mac_value;
+       int arp_validate_value, fail_over_mac_value, primary_reselect_value;
 
        /*
         * Convert string parameters.
@@ -4707,7 +4706,8 @@ static int bond_check_params(struct bond_params *params)
                if ((bond_mode != BOND_MODE_XOR) &&
                    (bond_mode != BOND_MODE_8023AD)) {
                        pr_info(DRV_NAME
-                              ": xor_mode param is irrelevant in mode %s\n",
+                               ": xmit_hash_policy param is irrelevant in"
+                               " mode %s\n",
                               bond_mode_name(bond_mode));
                } else {
                        xmit_hashtype = bond_parse_parm(xmit_hash_policy,
@@ -4755,7 +4755,7 @@ static int bond_check_params(struct bond_params *params)
                params->ad_select = BOND_AD_STABLE;
        }
 
-       if (max_bonds < 0 || max_bonds > INT_MAX) {
+       if (max_bonds < 0) {
                pr_warning(DRV_NAME
                       ": Warning: max_bonds (%d) not in range %d-%d, so it "
                       "was reset to BOND_DEFAULT_MAX_BONDS (%d)\n",
@@ -4837,7 +4837,7 @@ static int bond_check_params(struct bond_params *params)
        }
 
        if (bond_mode == BOND_MODE_ALB) {
-               printk(KERN_NOTICE DRV_NAME
+               pr_notice(DRV_NAME
                       ": In ALB mode you might experience client "
                       "disconnections upon reconnection of a link if the "
                       "bonding module updelay parameter (%d msec) is "
@@ -4961,9 +4961,9 @@ static int bond_check_params(struct bond_params *params)
                       arp_ip_count);
 
                for (i = 0; i < arp_ip_count; i++)
-                       printk(" %s", arp_ip_target[i]);
+                       pr_info(" %s", arp_ip_target[i]);
 
-               printk("\n");
+               pr_info("\n");
 
        } else if (max_bonds) {
                /* miimon and arp_interval not set, we need one so things
@@ -4987,6 +4987,20 @@ static int bond_check_params(struct bond_params *params)
                primary = NULL;
        }
 
+       if (primary && primary_reselect) {
+               primary_reselect_value = bond_parse_parm(primary_reselect,
+                                                        pri_reselect_tbl);
+               if (primary_reselect_value == -1) {
+                       pr_err(DRV_NAME
+                              ": Error: Invalid primary_reselect \"%s\"\n",
+                              primary_reselect ==
+                                       NULL ? "NULL" : primary_reselect);
+                       return -EINVAL;
+               }
+       } else {
+               primary_reselect_value = BOND_PRI_RESELECT_ALWAYS;
+       }
+
        if (fail_over_mac) {
                fail_over_mac_value = bond_parse_parm(fail_over_mac,
                                                      fail_over_mac_tbl);
@@ -5018,6 +5032,7 @@ static int bond_check_params(struct bond_params *params)
        params->use_carrier = use_carrier;
        params->lacp_fast = lacp_fast;
        params->primary[0] = 0;
+       params->primary_reselect = primary_reselect_value;
        params->fail_over_mac = fail_over_mac_value;
 
        if (primary) {