Merge branch 'x86-x32-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[cascardo/linux.git] / drivers / net / bonding / bond_sysfs.c
index 0ae580b..643fcc1 100644 (file)
@@ -12,8 +12,7 @@
  * for more details.
  *
  * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
  *
  * The full GNU General Public License is included in this distribution in the
  * file called LICENSE.
@@ -40,7 +39,6 @@
 #include <net/net_namespace.h>
 #include <net/netns/generic.h>
 #include <linux/nsproxy.h>
-#include <linux/reciprocal_div.h>
 
 #include "bonding.h"
 
@@ -202,58 +200,15 @@ static ssize_t bonding_store_slaves(struct device *d,
                                    struct device_attribute *attr,
                                    const char *buffer, size_t count)
 {
-       char command[IFNAMSIZ + 1] = { 0, };
-       char *ifname;
-       int res, ret = count;
-       struct net_device *dev;
        struct bonding *bond = to_bond(d);
+       int ret;
 
-       if (!rtnl_trylock())
-               return restart_syscall();
-
-       sscanf(buffer, "%16s", command); /* IFNAMSIZ*/
-       ifname = command + 1;
-       if ((strlen(command) <= 1) ||
-           !dev_valid_name(ifname))
-               goto err_no_cmd;
-
-       dev = __dev_get_by_name(dev_net(bond->dev), ifname);
-       if (!dev) {
-               pr_info("%s: Interface %s does not exist!\n",
-                       bond->dev->name, ifname);
-               ret = -ENODEV;
-               goto out;
-       }
-
-       switch (command[0]) {
-       case '+':
-               pr_info("%s: Adding slave %s.\n", bond->dev->name, dev->name);
-               res = bond_enslave(bond->dev, dev);
-               break;
-
-       case '-':
-               pr_info("%s: Removing slave %s.\n", bond->dev->name, dev->name);
-               res = bond_release(bond->dev, dev);
-               break;
-
-       default:
-               goto err_no_cmd;
-       }
-
-       if (res)
-               ret = res;
-       goto out;
-
-err_no_cmd:
-       pr_err("no command found in slaves file for bond %s. Use +ifname or -ifname.\n",
-              bond->dev->name);
-       ret = -EPERM;
+       ret = bond_opt_tryset_rtnl(bond, BOND_OPT_SLAVES, (char *)buffer);
+       if (!ret)
+               ret = count;
 
-out:
-       rtnl_unlock();
        return ret;
 }
-
 static DEVICE_ATTR(slaves, S_IRUGO | S_IWUSR, bonding_show_slaves,
                   bonding_store_slaves);
 
@@ -265,37 +220,24 @@ static ssize_t bonding_show_mode(struct device *d,
                                 struct device_attribute *attr, char *buf)
 {
        struct bonding *bond = to_bond(d);
+       struct bond_opt_value *val;
 
-       return sprintf(buf, "%s %d\n",
-                       bond_mode_tbl[bond->params.mode].modename,
-                       bond->params.mode);
+       val = bond_opt_get_val(BOND_OPT_MODE, bond->params.mode);
+
+       return sprintf(buf, "%s %d\n", val->string, bond->params.mode);
 }
 
 static ssize_t bonding_store_mode(struct device *d,
                                  struct device_attribute *attr,
                                  const char *buf, size_t count)
 {
-       int new_value, ret;
        struct bonding *bond = to_bond(d);
+       int ret;
 
-       new_value = bond_parse_parm(buf, bond_mode_tbl);
-       if (new_value < 0)  {
-               pr_err("%s: Ignoring invalid mode value %.*s.\n",
-                      bond->dev->name, (int)strlen(buf) - 1, buf);
-               return -EINVAL;
-       }
-       if (!rtnl_trylock())
-               return restart_syscall();
-
-       ret = bond_option_mode_set(bond, new_value);
-       if (!ret) {
-               pr_info("%s: setting mode to %s (%d).\n",
-                       bond->dev->name, bond_mode_tbl[new_value].modename,
-                       new_value);
+       ret = bond_opt_tryset_rtnl(bond, BOND_OPT_MODE, (char *)buf);
+       if (!ret)
                ret = count;
-       }
 
-       rtnl_unlock();
        return ret;
 }
 static DEVICE_ATTR(mode, S_IRUGO | S_IWUSR,
@@ -309,31 +251,23 @@ static ssize_t bonding_show_xmit_hash(struct device *d,
                                      char *buf)
 {
        struct bonding *bond = to_bond(d);
+       struct bond_opt_value *val;
 
-       return sprintf(buf, "%s %d\n",
-                      xmit_hashtype_tbl[bond->params.xmit_policy].modename,
-                      bond->params.xmit_policy);
+       val = bond_opt_get_val(BOND_OPT_XMIT_HASH, bond->params.xmit_policy);
+
+       return sprintf(buf, "%s %d\n", val->string, bond->params.xmit_policy);
 }
 
 static ssize_t bonding_store_xmit_hash(struct device *d,
                                       struct device_attribute *attr,
                                       const char *buf, size_t count)
 {
-       int new_value, ret = count;
        struct bonding *bond = to_bond(d);
+       int ret;
 
-       new_value = bond_parse_parm(buf, xmit_hashtype_tbl);
-       if (new_value < 0)  {
-               pr_err("%s: Ignoring invalid xmit hash policy value %.*s.\n",
-                      bond->dev->name,
-                      (int)strlen(buf) - 1, buf);
-               ret = -EINVAL;
-       } else {
-               bond->params.xmit_policy = new_value;
-               pr_info("%s: setting xmit hash policy to %s (%d).\n",
-                       bond->dev->name,
-                       xmit_hashtype_tbl[new_value].modename, new_value);
-       }
+       ret = bond_opt_tryset_rtnl(bond, BOND_OPT_XMIT_HASH, (char *)buf);
+       if (!ret)
+               ret = count;
 
        return ret;
 }
@@ -348,10 +282,12 @@ static ssize_t bonding_show_arp_validate(struct device *d,
                                         char *buf)
 {
        struct bonding *bond = to_bond(d);
+       struct bond_opt_value *val;
 
-       return sprintf(buf, "%s %d\n",
-                      arp_validate_tbl[bond->params.arp_validate].modename,
-                      bond->params.arp_validate);
+       val = bond_opt_get_val(BOND_OPT_ARP_VALIDATE,
+                              bond->params.arp_validate);
+
+       return sprintf(buf, "%s %d\n", val->string, bond->params.arp_validate);
 }
 
 static ssize_t bonding_store_arp_validate(struct device *d,
@@ -359,36 +295,11 @@ static ssize_t bonding_store_arp_validate(struct device *d,
                                          const char *buf, size_t count)
 {
        struct bonding *bond = to_bond(d);
-       int new_value, ret = count;
+       int ret;
 
-       if (!rtnl_trylock())
-               return restart_syscall();
-       new_value = bond_parse_parm(buf, arp_validate_tbl);
-       if (new_value < 0) {
-               pr_err("%s: Ignoring invalid arp_validate value %s\n",
-                      bond->dev->name, buf);
-               ret = -EINVAL;
-               goto out;
-       }
-       if (bond->params.mode != BOND_MODE_ACTIVEBACKUP) {
-               pr_err("%s: arp_validate only supported in active-backup mode.\n",
-                      bond->dev->name);
-               ret = -EINVAL;
-               goto out;
-       }
-       pr_info("%s: setting arp_validate to %s (%d).\n",
-               bond->dev->name, arp_validate_tbl[new_value].modename,
-               new_value);
-
-       if (bond->dev->flags & IFF_UP) {
-               if (!new_value)
-                       bond->recv_probe = NULL;
-               else if (bond->params.arp_interval)
-                       bond->recv_probe = bond_arp_rcv;
-       }
-       bond->params.arp_validate = new_value;
-out:
-       rtnl_unlock();
+       ret = bond_opt_tryset_rtnl(bond, BOND_OPT_ARP_VALIDATE, (char *)buf);
+       if (!ret)
+               ret = count;
 
        return ret;
 }
@@ -403,10 +314,12 @@ static ssize_t bonding_show_arp_all_targets(struct device *d,
                                         char *buf)
 {
        struct bonding *bond = to_bond(d);
-       int value = bond->params.arp_all_targets;
+       struct bond_opt_value *val;
 
-       return sprintf(buf, "%s %d\n", arp_all_targets_tbl[value].modename,
-                      value);
+       val = bond_opt_get_val(BOND_OPT_ARP_ALL_TARGETS,
+                              bond->params.arp_all_targets);
+       return sprintf(buf, "%s %d\n",
+                      val->string, bond->params.arp_all_targets);
 }
 
 static ssize_t bonding_store_arp_all_targets(struct device *d,
@@ -414,21 +327,13 @@ static ssize_t bonding_store_arp_all_targets(struct device *d,
                                          const char *buf, size_t count)
 {
        struct bonding *bond = to_bond(d);
-       int new_value;
-
-       new_value = bond_parse_parm(buf, arp_all_targets_tbl);
-       if (new_value < 0) {
-               pr_err("%s: Ignoring invalid arp_all_targets value %s\n",
-                      bond->dev->name, buf);
-               return -EINVAL;
-       }
-       pr_info("%s: setting arp_all_targets to %s (%d).\n",
-               bond->dev->name, arp_all_targets_tbl[new_value].modename,
-               new_value);
+       int ret;
 
-       bond->params.arp_all_targets = new_value;
+       ret = bond_opt_tryset_rtnl(bond, BOND_OPT_ARP_ALL_TARGETS, (char *)buf);
+       if (!ret)
+               ret = count;
 
-       return count;
+       return ret;
 }
 
 static DEVICE_ATTR(arp_all_targets, S_IRUGO | S_IWUSR,
@@ -443,44 +348,25 @@ static ssize_t bonding_show_fail_over_mac(struct device *d,
                                          char *buf)
 {
        struct bonding *bond = to_bond(d);
+       struct bond_opt_value *val;
 
-       return sprintf(buf, "%s %d\n",
-                      fail_over_mac_tbl[bond->params.fail_over_mac].modename,
-                      bond->params.fail_over_mac);
+       val = bond_opt_get_val(BOND_OPT_FAIL_OVER_MAC,
+                              bond->params.fail_over_mac);
+
+       return sprintf(buf, "%s %d\n", val->string, bond->params.fail_over_mac);
 }
 
 static ssize_t bonding_store_fail_over_mac(struct device *d,
                                           struct device_attribute *attr,
                                           const char *buf, size_t count)
 {
-       int new_value, ret = count;
        struct bonding *bond = to_bond(d);
+       int ret;
 
-       if (!rtnl_trylock())
-               return restart_syscall();
-
-       if (bond_has_slaves(bond)) {
-               pr_err("%s: Can't alter fail_over_mac with slaves in bond.\n",
-                      bond->dev->name);
-               ret = -EPERM;
-               goto out;
-       }
-
-       new_value = bond_parse_parm(buf, fail_over_mac_tbl);
-       if (new_value < 0) {
-               pr_err("%s: Ignoring invalid fail_over_mac value %s.\n",
-                      bond->dev->name, buf);
-               ret = -EINVAL;
-               goto out;
-       }
-
-       bond->params.fail_over_mac = new_value;
-       pr_info("%s: Setting fail_over_mac to %s (%d).\n",
-               bond->dev->name, fail_over_mac_tbl[new_value].modename,
-               new_value);
+       ret = bond_opt_tryset_rtnl(bond, BOND_OPT_FAIL_OVER_MAC, (char *)buf);
+       if (!ret)
+               ret = count;
 
-out:
-       rtnl_unlock();
        return ret;
 }
 
@@ -507,61 +393,12 @@ static ssize_t bonding_store_arp_interval(struct device *d,
                                          const char *buf, size_t count)
 {
        struct bonding *bond = to_bond(d);
-       int new_value, ret = count;
+       int ret;
+
+       ret = bond_opt_tryset_rtnl(bond, BOND_OPT_ARP_INTERVAL, (char *)buf);
+       if (!ret)
+               ret = count;
 
-       if (!rtnl_trylock())
-               return restart_syscall();
-       if (sscanf(buf, "%d", &new_value) != 1) {
-               pr_err("%s: no arp_interval value specified.\n",
-                      bond->dev->name);
-               ret = -EINVAL;
-               goto out;
-       }
-       if (new_value < 0) {
-               pr_err("%s: Invalid arp_interval value %d not in range 0-%d; rejected.\n",
-                      bond->dev->name, new_value, INT_MAX);
-               ret = -EINVAL;
-               goto out;
-       }
-       if (BOND_NO_USES_ARP(bond->params.mode)) {
-               pr_info("%s: ARP monitoring cannot be used with ALB/TLB/802.3ad. Only MII monitoring is supported on %s.\n",
-                       bond->dev->name, bond->dev->name);
-               ret = -EINVAL;
-               goto out;
-       }
-       pr_info("%s: Setting ARP monitoring interval to %d.\n",
-               bond->dev->name, new_value);
-       bond->params.arp_interval = new_value;
-       if (new_value) {
-               if (bond->params.miimon) {
-                       pr_info("%s: ARP monitoring cannot be used with MII monitoring. %s Disabling MII monitoring.\n",
-                               bond->dev->name, bond->dev->name);
-                       bond->params.miimon = 0;
-               }
-               if (!bond->params.arp_targets[0])
-                       pr_info("%s: ARP monitoring has been set up, but no ARP targets have been specified.\n",
-                               bond->dev->name);
-       }
-       if (bond->dev->flags & IFF_UP) {
-               /* If the interface is up, we may need to fire off
-                * the ARP timer.  If the interface is down, the
-                * timer will get fired off when the open function
-                * is called.
-                */
-               if (!new_value) {
-                       if (bond->params.arp_validate)
-                               bond->recv_probe = NULL;
-                       cancel_delayed_work_sync(&bond->arp_work);
-               } else {
-                       /* arp_validate can be set only in active-backup mode */
-                       if (bond->params.arp_validate)
-                               bond->recv_probe = bond_arp_rcv;
-                       cancel_delayed_work_sync(&bond->mii_work);
-                       queue_delayed_work(bond->wq, &bond->arp_work, 0);
-               }
-       }
-out:
-       rtnl_unlock();
        return ret;
 }
 static DEVICE_ATTR(arp_interval, S_IRUGO | S_IWUSR,
@@ -574,8 +411,8 @@ static ssize_t bonding_show_arp_targets(struct device *d,
                                        struct device_attribute *attr,
                                        char *buf)
 {
-       int i, res = 0;
        struct bonding *bond = to_bond(d);
+       int i, res = 0;
 
        for (i = 0; i < BOND_MAX_ARP_TARGETS; i++) {
                if (bond->params.arp_targets[i])
@@ -584,6 +421,7 @@ static ssize_t bonding_show_arp_targets(struct device *d,
        }
        if (res)
                buf[res-1] = '\n'; /* eat the leftover space */
+
        return res;
 }
 
@@ -592,82 +430,12 @@ static ssize_t bonding_store_arp_targets(struct device *d,
                                         const char *buf, size_t count)
 {
        struct bonding *bond = to_bond(d);
-       struct list_head *iter;
-       struct slave *slave;
-       __be32 newtarget, *targets;
-       unsigned long *targets_rx;
-       int ind, i, j, ret = -EINVAL;
-
-       if (!rtnl_trylock())
-               return restart_syscall();
-
-       targets = bond->params.arp_targets;
-       if (!in4_pton(buf + 1, -1, (u8 *)&newtarget, -1, NULL) ||
-           IS_IP_TARGET_UNUSABLE_ADDRESS(newtarget)) {
-               pr_err("%s: invalid ARP target %pI4 specified for addition\n",
-                      bond->dev->name, &newtarget);
-               goto out;
-       }
-       /* look for adds */
-       if (buf[0] == '+') {
-               if (bond_get_targets_ip(targets, newtarget) != -1) { /* dup */
-                       pr_err("%s: ARP target %pI4 is already present\n",
-                              bond->dev->name, &newtarget);
-                       goto out;
-               }
-
-               ind = bond_get_targets_ip(targets, 0); /* first free slot */
-               if (ind == -1) {
-                       pr_err("%s: ARP target table is full!\n",
-                              bond->dev->name);
-                       goto out;
-               }
-
-               pr_info("%s: adding ARP target %pI4.\n", bond->dev->name,
-                        &newtarget);
-               /* not to race with bond_arp_rcv */
-               write_lock_bh(&bond->lock);
-               bond_for_each_slave(bond, slave, iter)
-                       slave->target_last_arp_rx[ind] = jiffies;
-               targets[ind] = newtarget;
-               write_unlock_bh(&bond->lock);
-       } else if (buf[0] == '-')       {
-               ind = bond_get_targets_ip(targets, newtarget);
-               if (ind == -1) {
-                       pr_err("%s: unable to remove nonexistent ARP target %pI4.\n",
-                               bond->dev->name, &newtarget);
-                       goto out;
-               }
-
-               if (ind == 0 && !targets[1] && bond->params.arp_interval)
-                       pr_warn("%s: removing last arp target with arp_interval on\n",
-                               bond->dev->name);
-
-               pr_info("%s: removing ARP target %pI4.\n", bond->dev->name,
-                       &newtarget);
+       int ret;
 
-               write_lock_bh(&bond->lock);
-               bond_for_each_slave(bond, slave, iter) {
-                       targets_rx = slave->target_last_arp_rx;
-                       j = ind;
-                       for (; (j < BOND_MAX_ARP_TARGETS-1) && targets[j+1]; j++)
-                               targets_rx[j] = targets_rx[j+1];
-                       targets_rx[j] = 0;
-               }
-               for (i = ind; (i < BOND_MAX_ARP_TARGETS-1) && targets[i+1]; i++)
-                       targets[i] = targets[i+1];
-               targets[i] = 0;
-               write_unlock_bh(&bond->lock);
-       } else {
-               pr_err("no command found in arp_ip_targets file for bond %s. Use +<addr> or -<addr>.\n",
-                      bond->dev->name);
-               ret = -EPERM;
-               goto out;
-       }
+       ret = bond_opt_tryset_rtnl(bond, BOND_OPT_ARP_TARGETS, (char *)buf);
+       if (!ret)
+               ret = count;
 
-       ret = count;
-out:
-       rtnl_unlock();
        return ret;
 }
 static DEVICE_ATTR(arp_ip_target, S_IRUGO | S_IWUSR , bonding_show_arp_targets, bonding_store_arp_targets);
@@ -690,45 +458,13 @@ static ssize_t bonding_store_downdelay(struct device *d,
                                       struct device_attribute *attr,
                                       const char *buf, size_t count)
 {
-       int new_value, ret = count;
        struct bonding *bond = to_bond(d);
+       int ret;
 
-       if (!rtnl_trylock())
-               return restart_syscall();
-       if (!(bond->params.miimon)) {
-               pr_err("%s: Unable to set down delay as MII monitoring is disabled\n",
-                      bond->dev->name);
-               ret = -EPERM;
-               goto out;
-       }
-
-       if (sscanf(buf, "%d", &new_value) != 1) {
-               pr_err("%s: no down delay value specified.\n", bond->dev->name);
-               ret = -EINVAL;
-               goto out;
-       }
-       if (new_value < 0) {
-               pr_err("%s: Invalid down delay value %d not in range %d-%d; rejected.\n",
-                      bond->dev->name, new_value, 0, INT_MAX);
-               ret = -EINVAL;
-               goto out;
-       } else {
-               if ((new_value % bond->params.miimon) != 0) {
-                       pr_warning("%s: Warning: down delay (%d) is not a multiple of miimon (%d), delay rounded to %d ms\n",
-                                  bond->dev->name, new_value,
-                                  bond->params.miimon,
-                                  (new_value / bond->params.miimon) *
-                                  bond->params.miimon);
-               }
-               bond->params.downdelay = new_value / bond->params.miimon;
-               pr_info("%s: Setting down delay to %d.\n",
-                       bond->dev->name,
-                       bond->params.downdelay * bond->params.miimon);
-
-       }
+       ret = bond_opt_tryset_rtnl(bond, BOND_OPT_DOWNDELAY, (char *)buf);
+       if (!ret)
+               ret = count;
 
-out:
-       rtnl_unlock();
        return ret;
 }
 static DEVICE_ATTR(downdelay, S_IRUGO | S_IWUSR,
@@ -748,45 +484,13 @@ static ssize_t bonding_store_updelay(struct device *d,
                                     struct device_attribute *attr,
                                     const char *buf, size_t count)
 {
-       int new_value, ret = count;
        struct bonding *bond = to_bond(d);
+       int ret;
 
-       if (!rtnl_trylock())
-               return restart_syscall();
-       if (!(bond->params.miimon)) {
-               pr_err("%s: Unable to set up delay as MII monitoring is disabled\n",
-                      bond->dev->name);
-               ret = -EPERM;
-               goto out;
-       }
-
-       if (sscanf(buf, "%d", &new_value) != 1) {
-               pr_err("%s: no up delay value specified.\n",
-                      bond->dev->name);
-               ret = -EINVAL;
-               goto out;
-       }
-       if (new_value < 0) {
-               pr_err("%s: Invalid up delay value %d not in range %d-%d; rejected.\n",
-                      bond->dev->name, new_value, 0, INT_MAX);
-               ret = -EINVAL;
-               goto out;
-       } else {
-               if ((new_value % bond->params.miimon) != 0) {
-                       pr_warning("%s: Warning: up delay (%d) is not a multiple of miimon (%d), updelay rounded to %d ms\n",
-                                  bond->dev->name, new_value,
-                                  bond->params.miimon,
-                                  (new_value / bond->params.miimon) *
-                                  bond->params.miimon);
-               }
-               bond->params.updelay = new_value / bond->params.miimon;
-               pr_info("%s: Setting up delay to %d.\n",
-                       bond->dev->name,
-                       bond->params.updelay * bond->params.miimon);
-       }
+       ret = bond_opt_tryset_rtnl(bond, BOND_OPT_UPDELAY, (char *)buf);
+       if (!ret)
+               ret = count;
 
-out:
-       rtnl_unlock();
        return ret;
 }
 static DEVICE_ATTR(updelay, S_IRUGO | S_IWUSR,
@@ -801,10 +505,11 @@ static ssize_t bonding_show_lacp(struct device *d,
                                 char *buf)
 {
        struct bonding *bond = to_bond(d);
+       struct bond_opt_value *val;
 
-       return sprintf(buf, "%s %d\n",
-               bond_lacp_tbl[bond->params.lacp_fast].modename,
-               bond->params.lacp_fast);
+       val = bond_opt_get_val(BOND_OPT_LACP_RATE, bond->params.lacp_fast);
+
+       return sprintf(buf, "%s %d\n", val->string, bond->params.lacp_fast);
 }
 
 static ssize_t bonding_store_lacp(struct device *d,
@@ -812,40 +517,11 @@ static ssize_t bonding_store_lacp(struct device *d,
                                  const char *buf, size_t count)
 {
        struct bonding *bond = to_bond(d);
-       int new_value, ret = count;
-
-       if (!rtnl_trylock())
-               return restart_syscall();
-
-       if (bond->dev->flags & IFF_UP) {
-               pr_err("%s: Unable to update LACP rate because interface is up.\n",
-                      bond->dev->name);
-               ret = -EPERM;
-               goto out;
-       }
-
-       if (bond->params.mode != BOND_MODE_8023AD) {
-               pr_err("%s: Unable to update LACP rate because bond is not in 802.3ad mode.\n",
-                      bond->dev->name);
-               ret = -EPERM;
-               goto out;
-       }
+       int ret;
 
-       new_value = bond_parse_parm(buf, bond_lacp_tbl);
-
-       if ((new_value == 1) || (new_value == 0)) {
-               bond->params.lacp_fast = new_value;
-               bond_3ad_update_lacp_rate(bond);
-               pr_info("%s: Setting LACP rate to %s (%d).\n",
-                       bond->dev->name, bond_lacp_tbl[new_value].modename,
-                       new_value);
-       } else {
-               pr_err("%s: Ignoring invalid LACP rate value %.*s.\n",
-                      bond->dev->name, (int)strlen(buf) - 1, buf);
-               ret = -EINVAL;
-       }
-out:
-       rtnl_unlock();
+       ret = bond_opt_tryset_rtnl(bond, BOND_OPT_LACP_RATE, (char *)buf);
+       if (!ret)
+               ret = count;
 
        return ret;
 }
@@ -867,19 +543,12 @@ static ssize_t bonding_store_min_links(struct device *d,
 {
        struct bonding *bond = to_bond(d);
        int ret;
-       unsigned int new_value;
 
-       ret = kstrtouint(buf, 0, &new_value);
-       if (ret < 0) {
-               pr_err("%s: Ignoring invalid min links value %s.\n",
-                      bond->dev->name, buf);
-               return ret;
-       }
+       ret = bond_opt_tryset_rtnl(bond, BOND_OPT_MINLINKS, (char *)buf);
+       if (!ret)
+               ret = count;
 
-       pr_info("%s: Setting min links value to %u\n",
-               bond->dev->name, new_value);
-       bond->params.min_links = new_value;
-       return count;
+       return ret;
 }
 static DEVICE_ATTR(min_links, S_IRUGO | S_IWUSR,
                   bonding_show_min_links, bonding_store_min_links);
@@ -889,10 +558,11 @@ static ssize_t bonding_show_ad_select(struct device *d,
                                      char *buf)
 {
        struct bonding *bond = to_bond(d);
+       struct bond_opt_value *val;
 
-       return sprintf(buf, "%s %d\n",
-               ad_select_tbl[bond->params.ad_select].modename,
-               bond->params.ad_select);
+       val = bond_opt_get_val(BOND_OPT_AD_SELECT, bond->params.ad_select);
+
+       return sprintf(buf, "%s %d\n", val->string, bond->params.ad_select);
 }
 
 
@@ -900,29 +570,13 @@ static ssize_t bonding_store_ad_select(struct device *d,
                                       struct device_attribute *attr,
                                       const char *buf, size_t count)
 {
-       int new_value, ret = count;
        struct bonding *bond = to_bond(d);
+       int ret;
 
-       if (bond->dev->flags & IFF_UP) {
-               pr_err("%s: Unable to update ad_select because interface is up.\n",
-                      bond->dev->name);
-               ret = -EPERM;
-               goto out;
-       }
+       ret = bond_opt_tryset_rtnl(bond, BOND_OPT_AD_SELECT, (char *)buf);
+       if (!ret)
+               ret = count;
 
-       new_value = bond_parse_parm(buf, ad_select_tbl);
-
-       if (new_value != -1) {
-               bond->params.ad_select = new_value;
-               pr_info("%s: Setting ad_select to %s (%d).\n",
-                       bond->dev->name, ad_select_tbl[new_value].modename,
-                       new_value);
-       } else {
-               pr_err("%s: Ignoring invalid ad_select value %.*s.\n",
-                      bond->dev->name, (int)strlen(buf) - 1, buf);
-               ret = -EINVAL;
-       }
-out:
        return ret;
 }
 static DEVICE_ATTR(ad_select, S_IRUGO | S_IWUSR,
@@ -944,8 +598,13 @@ static ssize_t bonding_store_num_peer_notif(struct device *d,
                                            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;
+       int ret;
+
+       ret = bond_opt_tryset_rtnl(bond, BOND_OPT_NUM_PEER_NOTIF, (char *)buf);
+       if (!ret)
+               ret = count;
+
+       return ret;
 }
 static DEVICE_ATTR(num_grat_arp, S_IRUGO | S_IWUSR,
                   bonding_show_num_peer_notif, bonding_store_num_peer_notif);
@@ -971,56 +630,13 @@ static ssize_t bonding_store_miimon(struct device *d,
                                    struct device_attribute *attr,
                                    const char *buf, size_t count)
 {
-       int new_value, ret = count;
        struct bonding *bond = to_bond(d);
+       int ret;
+
+       ret = bond_opt_tryset_rtnl(bond, BOND_OPT_MIIMON, (char *)buf);
+       if (!ret)
+               ret = count;
 
-       if (!rtnl_trylock())
-               return restart_syscall();
-       if (sscanf(buf, "%d", &new_value) != 1) {
-               pr_err("%s: no miimon value specified.\n",
-                      bond->dev->name);
-               ret = -EINVAL;
-               goto out;
-       }
-       if (new_value < 0) {
-               pr_err("%s: Invalid miimon value %d not in range %d-%d; rejected.\n",
-                      bond->dev->name, new_value, 0, INT_MAX);
-               ret = -EINVAL;
-               goto out;
-       }
-       pr_info("%s: Setting MII monitoring interval to %d.\n",
-               bond->dev->name, new_value);
-       bond->params.miimon = new_value;
-       if (bond->params.updelay)
-               pr_info("%s: Note: Updating updelay (to %d) since it is a multiple of the miimon value.\n",
-                       bond->dev->name,
-                       bond->params.updelay * bond->params.miimon);
-       if (bond->params.downdelay)
-               pr_info("%s: Note: Updating downdelay (to %d) since it is a multiple of the miimon value.\n",
-                       bond->dev->name,
-                       bond->params.downdelay * bond->params.miimon);
-       if (new_value && bond->params.arp_interval) {
-               pr_info("%s: MII monitoring cannot be used with ARP monitoring. Disabling ARP monitoring...\n",
-                       bond->dev->name);
-               bond->params.arp_interval = 0;
-               if (bond->params.arp_validate)
-                       bond->params.arp_validate = BOND_ARP_VALIDATE_NONE;
-       }
-       if (bond->dev->flags & IFF_UP) {
-               /* If the interface is up, we may need to fire off
-                * the MII timer. If the interface is down, the
-                * timer will get fired off when the open function
-                * is called.
-                */
-               if (!new_value) {
-                       cancel_delayed_work_sync(&bond->mii_work);
-               } else {
-                       cancel_delayed_work_sync(&bond->arp_work);
-                       queue_delayed_work(bond->wq, &bond->mii_work, 0);
-               }
-       }
-out:
-       rtnl_unlock();
        return ret;
 }
 static DEVICE_ATTR(miimon, S_IRUGO | S_IWUSR,
@@ -1051,58 +667,13 @@ static ssize_t bonding_store_primary(struct device *d,
                                     const char *buf, size_t count)
 {
        struct bonding *bond = to_bond(d);
-       struct list_head *iter;
-       char ifname[IFNAMSIZ];
-       struct slave *slave;
-
-       if (!rtnl_trylock())
-               return restart_syscall();
-       block_netpoll_tx();
-       read_lock(&bond->lock);
-       write_lock_bh(&bond->curr_slave_lock);
-
-       if (!USES_PRIMARY(bond->params.mode)) {
-               pr_info("%s: Unable to set primary slave; %s is in mode %d\n",
-                       bond->dev->name, bond->dev->name, bond->params.mode);
-               goto out;
-       }
-
-       sscanf(buf, "%15s", ifname); /* IFNAMSIZ */
-
-       /* check to see if we are clearing primary */
-       if (!strlen(ifname) || buf[0] == '\n') {
-               pr_info("%s: Setting primary slave to None.\n",
-                       bond->dev->name);
-               bond->primary_slave = NULL;
-               memset(bond->params.primary, 0, sizeof(bond->params.primary));
-               bond_select_active_slave(bond);
-               goto out;
-       }
-
-       bond_for_each_slave(bond, slave, iter) {
-               if (strncmp(slave->dev->name, ifname, IFNAMSIZ) == 0) {
-                       pr_info("%s: Setting %s as primary slave.\n",
-                               bond->dev->name, slave->dev->name);
-                       bond->primary_slave = slave;
-                       strcpy(bond->params.primary, slave->dev->name);
-                       bond_select_active_slave(bond);
-                       goto out;
-               }
-       }
-
-       strncpy(bond->params.primary, ifname, IFNAMSIZ);
-       bond->params.primary[IFNAMSIZ - 1] = 0;
+       int ret;
 
-       pr_info("%s: Recording %s as primary, "
-               "but it has not been enslaved to %s yet.\n",
-               bond->dev->name, ifname, bond->dev->name);
-out:
-       write_unlock_bh(&bond->curr_slave_lock);
-       read_unlock(&bond->lock);
-       unblock_netpoll_tx();
-       rtnl_unlock();
+       ret = bond_opt_tryset_rtnl(bond, BOND_OPT_PRIMARY, (char *)buf);
+       if (!ret)
+               ret = count;
 
-       return count;
+       return ret;
 }
 static DEVICE_ATTR(primary, S_IRUGO | S_IWUSR,
                   bonding_show_primary, bonding_store_primary);
@@ -1115,45 +686,27 @@ static ssize_t bonding_show_primary_reselect(struct device *d,
                                             char *buf)
 {
        struct bonding *bond = to_bond(d);
+       struct bond_opt_value *val;
+
+       val = bond_opt_get_val(BOND_OPT_PRIMARY_RESELECT,
+                              bond->params.primary_reselect);
 
        return sprintf(buf, "%s %d\n",
-                      pri_reselect_tbl[bond->params.primary_reselect].modename,
-                      bond->params.primary_reselect);
+                      val->string, bond->params.primary_reselect);
 }
 
 static ssize_t bonding_store_primary_reselect(struct device *d,
                                              struct device_attribute *attr,
                                              const char *buf, size_t count)
 {
-       int new_value, ret = count;
        struct bonding *bond = to_bond(d);
+       int ret;
 
-       if (!rtnl_trylock())
-               return restart_syscall();
-
-       new_value = bond_parse_parm(buf, pri_reselect_tbl);
-       if (new_value < 0)  {
-               pr_err("%s: Ignoring invalid primary_reselect value %.*s.\n",
-                      bond->dev->name,
-                      (int) strlen(buf) - 1, buf);
-               ret = -EINVAL;
-               goto out;
-       }
+       ret = bond_opt_tryset_rtnl(bond, BOND_OPT_PRIMARY_RESELECT,
+                                  (char *)buf);
+       if (!ret)
+               ret = count;
 
-       bond->params.primary_reselect = new_value;
-       pr_info("%s: setting primary_reselect to %s (%d).\n",
-               bond->dev->name, pri_reselect_tbl[new_value].modename,
-               new_value);
-
-       block_netpoll_tx();
-       read_lock(&bond->lock);
-       write_lock_bh(&bond->curr_slave_lock);
-       bond_select_active_slave(bond);
-       write_unlock_bh(&bond->curr_slave_lock);
-       read_unlock(&bond->lock);
-       unblock_netpoll_tx();
-out:
-       rtnl_unlock();
        return ret;
 }
 static DEVICE_ATTR(primary_reselect, S_IRUGO | S_IWUSR,
@@ -1176,25 +729,13 @@ static ssize_t bonding_store_carrier(struct device *d,
                                     struct device_attribute *attr,
                                     const char *buf, size_t count)
 {
-       int new_value, ret = count;
        struct bonding *bond = to_bond(d);
+       int ret;
 
+       ret = bond_opt_tryset_rtnl(bond, BOND_OPT_USE_CARRIER, (char *)buf);
+       if (!ret)
+               ret = count;
 
-       if (sscanf(buf, "%d", &new_value) != 1) {
-               pr_err("%s: no use_carrier value specified.\n",
-                      bond->dev->name);
-               ret = -EINVAL;
-               goto out;
-       }
-       if ((new_value == 0) || (new_value == 1)) {
-               bond->params.use_carrier = new_value;
-               pr_info("%s: Setting use_carrier to %d.\n",
-                       bond->dev->name, new_value);
-       } else {
-               pr_info("%s: Ignoring invalid use_carrier value %d.\n",
-                       bond->dev->name, new_value);
-       }
-out:
        return ret;
 }
 static DEVICE_ATTR(use_carrier, S_IRUGO | S_IWUSR,
@@ -1225,34 +766,14 @@ static ssize_t bonding_store_active_slave(struct device *d,
                                          struct device_attribute *attr,
                                          const char *buf, size_t count)
 {
-       int ret;
        struct bonding *bond = to_bond(d);
-       char ifname[IFNAMSIZ];
-       struct net_device *dev;
-
-       if (!rtnl_trylock())
-               return restart_syscall();
-
-       sscanf(buf, "%15s", ifname); /* IFNAMSIZ */
-       if (!strlen(ifname) || buf[0] == '\n') {
-               dev = NULL;
-       } else {
-               dev = __dev_get_by_name(dev_net(bond->dev), ifname);
-               if (!dev) {
-                       ret = -ENODEV;
-                       goto out;
-               }
-       }
+       int ret;
 
-       ret = bond_option_active_slave_set(bond, dev);
+       ret = bond_opt_tryset_rtnl(bond, BOND_OPT_ACTIVE_SLAVE, (char *)buf);
        if (!ret)
                ret = count;
 
- out:
-       rtnl_unlock();
-
        return ret;
-
 }
 static DEVICE_ATTR(active_slave, S_IRUGO | S_IWUSR,
                   bonding_show_active_slave, bonding_store_active_slave);
@@ -1421,72 +942,15 @@ static ssize_t bonding_store_queue_id(struct device *d,
                                      struct device_attribute *attr,
                                      const char *buffer, size_t count)
 {
-       struct slave *slave, *update_slave;
        struct bonding *bond = to_bond(d);
-       struct list_head *iter;
-       u16 qid;
-       int ret = count;
-       char *delim;
-       struct net_device *sdev = NULL;
-
-       if (!rtnl_trylock())
-               return restart_syscall();
-
-       /* delim will point to queue id if successful */
-       delim = strchr(buffer, ':');
-       if (!delim)
-               goto err_no_cmd;
-
-       /*
-        * Terminate string that points to device name and bump it
-        * up one, so we can read the queue id there.
-        */
-       *delim = '\0';
-       if (sscanf(++delim, "%hd\n", &qid) != 1)
-               goto err_no_cmd;
-
-       /* Check buffer length, valid ifname and queue id */
-       if (strlen(buffer) > IFNAMSIZ ||
-           !dev_valid_name(buffer) ||
-           qid > bond->dev->real_num_tx_queues)
-               goto err_no_cmd;
-
-       /* Get the pointer to that interface if it exists */
-       sdev = __dev_get_by_name(dev_net(bond->dev), buffer);
-       if (!sdev)
-               goto err_no_cmd;
-
-       /* Search for thes slave and check for duplicate qids */
-       update_slave = NULL;
-       bond_for_each_slave(bond, slave, iter) {
-               if (sdev == slave->dev)
-                       /*
-                        * We don't need to check the matching
-                        * slave for dups, since we're overwriting it
-                        */
-                       update_slave = slave;
-               else if (qid && qid == slave->queue_id) {
-                       goto err_no_cmd;
-               }
-       }
-
-       if (!update_slave)
-               goto err_no_cmd;
+       int ret;
 
-       /* Actually set the qids for the slave */
-       update_slave->queue_id = qid;
+       ret = bond_opt_tryset_rtnl(bond, BOND_OPT_QUEUE_ID, (char *)buffer);
+       if (!ret)
+               ret = count;
 
-out:
-       rtnl_unlock();
        return ret;
-
-err_no_cmd:
-       pr_info("invalid input for queue_id set for %s.\n",
-               bond->dev->name);
-       ret = -EPERM;
-       goto out;
 }
-
 static DEVICE_ATTR(queue_id, S_IRUGO | S_IWUSR, bonding_show_queue_id,
                   bonding_store_queue_id);
 
@@ -1508,42 +972,13 @@ static ssize_t bonding_store_slaves_active(struct device *d,
                                           const char *buf, size_t count)
 {
        struct bonding *bond = to_bond(d);
-       int new_value, ret = count;
-       struct list_head *iter;
-       struct slave *slave;
-
-       if (!rtnl_trylock())
-               return restart_syscall();
-
-       if (sscanf(buf, "%d", &new_value) != 1) {
-               pr_err("%s: no all_slaves_active value specified.\n",
-                      bond->dev->name);
-               ret = -EINVAL;
-               goto out;
-       }
-
-       if (new_value == bond->params.all_slaves_active)
-               goto out;
+       int ret;
 
-       if ((new_value == 0) || (new_value == 1)) {
-               bond->params.all_slaves_active = new_value;
-       } else {
-               pr_info("%s: Ignoring invalid all_slaves_active value %d.\n",
-                       bond->dev->name, new_value);
-               ret = -EINVAL;
-               goto out;
-       }
+       ret = bond_opt_tryset_rtnl(bond, BOND_OPT_ALL_SLAVES_ACTIVE,
+                                  (char *)buf);
+       if (!ret)
+               ret = count;
 
-       bond_for_each_slave(bond, slave, iter) {
-               if (!bond_is_active_slave(slave)) {
-                       if (new_value)
-                               slave->inactive = 0;
-                       else
-                               slave->inactive = 1;
-               }
-       }
-out:
-       rtnl_unlock();
        return ret;
 }
 static DEVICE_ATTR(all_slaves_active, S_IRUGO | S_IWUSR,
@@ -1565,27 +1000,13 @@ static ssize_t bonding_store_resend_igmp(struct device *d,
                                         struct device_attribute *attr,
                                         const char *buf, size_t count)
 {
-       int new_value, ret = count;
        struct bonding *bond = to_bond(d);
+       int ret;
 
-       if (sscanf(buf, "%d", &new_value) != 1) {
-               pr_err("%s: no resend_igmp value specified.\n",
-                      bond->dev->name);
-               ret = -EINVAL;
-               goto out;
-       }
-
-       if (new_value < 0 || new_value > 255) {
-               pr_err("%s: Invalid resend_igmp value %d not in range 0-255; rejected.\n",
-                      bond->dev->name, new_value);
-               ret = -EINVAL;
-               goto out;
-       }
+       ret = bond_opt_tryset_rtnl(bond, BOND_OPT_RESEND_IGMP, (char *)buf);
+       if (!ret)
+               ret = count;
 
-       pr_info("%s: Setting resend_igmp to %d.\n",
-               bond->dev->name, new_value);
-       bond->params.resend_igmp = new_value;
-out:
        return ret;
 }
 
@@ -1606,24 +1027,12 @@ static ssize_t bonding_store_lp_interval(struct device *d,
                                         const char *buf, size_t count)
 {
        struct bonding *bond = to_bond(d);
-       int new_value, ret = count;
-
-       if (sscanf(buf, "%d", &new_value) != 1) {
-               pr_err("%s: no lp interval value specified.\n",
-                       bond->dev->name);
-               ret = -EINVAL;
-               goto out;
-       }
+       int ret;
 
-       if (new_value <= 0) {
-               pr_err ("%s: lp_interval must be between 1 and %d\n",
-                       bond->dev->name, INT_MAX);
-               ret = -EINVAL;
-               goto out;
-       }
+       ret = bond_opt_tryset_rtnl(bond, BOND_OPT_LP_INTERVAL, (char *)buf);
+       if (!ret)
+               ret = count;
 
-       bond->params.lp_interval = new_value;
-out:
        return ret;
 }
 
@@ -1636,10 +1045,6 @@ static ssize_t bonding_show_packets_per_slave(struct device *d,
 {
        struct bonding *bond = to_bond(d);
        unsigned int packets_per_slave = bond->params.packets_per_slave;
-
-       if (packets_per_slave > 1)
-               packets_per_slave = reciprocal_value(packets_per_slave);
-
        return sprintf(buf, "%u\n", packets_per_slave);
 }
 
@@ -1648,28 +1053,13 @@ static ssize_t bonding_store_packets_per_slave(struct device *d,
                                               const char *buf, size_t count)
 {
        struct bonding *bond = to_bond(d);
-       int new_value, ret = count;
+       int ret;
+
+       ret = bond_opt_tryset_rtnl(bond, BOND_OPT_PACKETS_PER_SLAVE,
+                                  (char *)buf);
+       if (!ret)
+               ret = count;
 
-       if (sscanf(buf, "%d", &new_value) != 1) {
-               pr_err("%s: no packets_per_slave value specified.\n",
-                      bond->dev->name);
-               ret = -EINVAL;
-               goto out;
-       }
-       if (new_value < 0 || new_value > USHRT_MAX) {
-               pr_err("%s: packets_per_slave must be between 0 and %u\n",
-                      bond->dev->name, USHRT_MAX);
-               ret = -EINVAL;
-               goto out;
-       }
-       if (bond->params.mode != BOND_MODE_ROUNDROBIN)
-               pr_warn("%s: Warning: packets_per_slave has effect only in balance-rr mode\n",
-                       bond->dev->name);
-       if (new_value > 1)
-               bond->params.packets_per_slave = reciprocal_value(new_value);
-       else
-               bond->params.packets_per_slave = new_value;
-out:
        return ret;
 }