Commit b414ac9a authored by David S. Miller's avatar David S. Miller

Merge branch 'bonding_option_api'

Nikolay Aleksandrov says:

====================
bonding: introduce new option API

This patchset's goal is to introduce a new option API which should be used
to properly describe the bonding options with their mode dependcies and
requirements. With this patchset applied we get centralized option
manipulation, automatic RTNL acquire per option setting, automatic option
range checking, mode dependcy checking and other various flags which are
described in detail in patch 01's commit message and comments.
Also the parameter passing is changed to use a specialized structure which
is initialized to a value depending on the needs.
The main exported functions are:
 __bond_opt_set() - set an option (RTNL should be acquired prior)
 bond_opt_init(val|str) - init a bond_opt_value struct for value or string
                          parameter passing
 bond_opt_tryset_rtnl() - function which tries to acquire rtnl, mainly used
                          for sysfs
 bond_opt_parse - used to parse or check for valid values
 bond_opt_get - retrieve a pointer to bond_option struct for some option
 bond_opt_get_val - retrieve a pointer to a bond_opt_value struct for
                    some value

The same functions are used to set an option via sysfs and netlink, just
the parameter that's passed is usually initialized in a different way.
The converted options have multiple style fixes, there're some longer
lines but they looked either ugly or were strings/pr_warnings, if you
think some line would be better broken just let me know :-) there're
also a few sscanf false-positive warnings.
I decided to keep the "unsuppmodes" way of mode dep checking since it's
straight forward, if we make a more general way for checking dependencies
it'll be easy to change it.

Future plans for this work include:
 - Automatic sysfs generation from the bond_opts[].
 - Use of the API in bond_check_params() and thus cleaning it up (this has
   actually started, I'll take care of the rest in a separate patch)
 - Clean up all option-unrelated files of option definitions and functions

I've tried to leave as much documentation as possible, if there's anything
unclear please let me know. One more thing, I haven't moved all
option-related functions from bonding.h to the new bond_options.h, this
will be done in a separate patch, it's in my todo list.

This patchset has been tested by setting each converted option via sysfs
and netlink to a couple of wrong values, a couple of correct values and
some random values, also for the opts that have flags they have been
tested as well.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 374d1125 0e2e5b66
...@@ -86,13 +86,11 @@ ...@@ -86,13 +86,11 @@
/*---------------------------- Module parameters ----------------------------*/ /*---------------------------- Module parameters ----------------------------*/
/* monitor all links that often (in milliseconds). <=0 disables monitoring */ /* monitor all links that often (in milliseconds). <=0 disables monitoring */
#define BOND_LINK_MON_INTERV 0
#define BOND_LINK_ARP_INTERV 0
static int max_bonds = BOND_DEFAULT_MAX_BONDS; static int max_bonds = BOND_DEFAULT_MAX_BONDS;
static int tx_queues = BOND_DEFAULT_TX_QUEUES; static int tx_queues = BOND_DEFAULT_TX_QUEUES;
static int num_peer_notif = 1; static int num_peer_notif = 1;
static int miimon = BOND_LINK_MON_INTERV; static int miimon;
static int updelay; static int updelay;
static int downdelay; static int downdelay;
static int use_carrier = 1; static int use_carrier = 1;
...@@ -103,7 +101,7 @@ static char *lacp_rate; ...@@ -103,7 +101,7 @@ static char *lacp_rate;
static int min_links; static int min_links;
static char *ad_select; static char *ad_select;
static char *xmit_hash_policy; static char *xmit_hash_policy;
static int arp_interval = BOND_LINK_ARP_INTERV; static int arp_interval;
static char *arp_ip_target[BOND_MAX_ARP_TARGETS]; static char *arp_ip_target[BOND_MAX_ARP_TARGETS];
static char *arp_validate; static char *arp_validate;
static char *arp_all_targets; static char *arp_all_targets;
...@@ -208,67 +206,6 @@ static int bond_mode = BOND_MODE_ROUNDROBIN; ...@@ -208,67 +206,6 @@ static int bond_mode = BOND_MODE_ROUNDROBIN;
static int xmit_hashtype = BOND_XMIT_POLICY_LAYER2; static int xmit_hashtype = BOND_XMIT_POLICY_LAYER2;
static int lacp_fast; static int lacp_fast;
const struct bond_parm_tbl bond_lacp_tbl[] = {
{ "slow", AD_LACP_SLOW},
{ "fast", AD_LACP_FAST},
{ NULL, -1},
};
const struct bond_parm_tbl bond_mode_tbl[] = {
{ "balance-rr", BOND_MODE_ROUNDROBIN},
{ "active-backup", BOND_MODE_ACTIVEBACKUP},
{ "balance-xor", BOND_MODE_XOR},
{ "broadcast", BOND_MODE_BROADCAST},
{ "802.3ad", BOND_MODE_8023AD},
{ "balance-tlb", BOND_MODE_TLB},
{ "balance-alb", BOND_MODE_ALB},
{ NULL, -1},
};
const struct bond_parm_tbl xmit_hashtype_tbl[] = {
{ "layer2", BOND_XMIT_POLICY_LAYER2},
{ "layer3+4", BOND_XMIT_POLICY_LAYER34},
{ "layer2+3", BOND_XMIT_POLICY_LAYER23},
{ "encap2+3", BOND_XMIT_POLICY_ENCAP23},
{ "encap3+4", BOND_XMIT_POLICY_ENCAP34},
{ NULL, -1},
};
const struct bond_parm_tbl arp_all_targets_tbl[] = {
{ "any", BOND_ARP_TARGETS_ANY},
{ "all", BOND_ARP_TARGETS_ALL},
{ NULL, -1},
};
const struct bond_parm_tbl arp_validate_tbl[] = {
{ "none", BOND_ARP_VALIDATE_NONE},
{ "active", BOND_ARP_VALIDATE_ACTIVE},
{ "backup", BOND_ARP_VALIDATE_BACKUP},
{ "all", BOND_ARP_VALIDATE_ALL},
{ NULL, -1},
};
const struct bond_parm_tbl fail_over_mac_tbl[] = {
{ "none", BOND_FOM_NONE},
{ "active", BOND_FOM_ACTIVE},
{ "follow", BOND_FOM_FOLLOW},
{ 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},
{ "count", BOND_AD_COUNT},
{ NULL, -1},
};
/*-------------------------- Forward declarations ---------------------------*/ /*-------------------------- Forward declarations ---------------------------*/
static int bond_init(struct net_device *bond_dev); static int bond_init(struct net_device *bond_dev);
...@@ -3186,6 +3123,7 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd ...@@ -3186,6 +3123,7 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd
struct ifslave k_sinfo; struct ifslave k_sinfo;
struct ifslave __user *u_sinfo = NULL; struct ifslave __user *u_sinfo = NULL;
struct mii_ioctl_data *mii = NULL; struct mii_ioctl_data *mii = NULL;
struct bond_opt_value newval;
struct net *net; struct net *net;
int res = 0; int res = 0;
...@@ -3281,7 +3219,8 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd ...@@ -3281,7 +3219,8 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd
break; break;
case BOND_CHANGE_ACTIVE_OLD: case BOND_CHANGE_ACTIVE_OLD:
case SIOCBONDCHANGEACTIVE: case SIOCBONDCHANGEACTIVE:
res = bond_option_active_slave_set(bond, slave_dev); bond_opt_initstr(&newval, slave_dev->name);
res = __bond_opt_set(bond, BOND_OPT_ACTIVE_SLAVE, &newval);
break; break;
default: default:
res = -EOPNOTSUPP; res = -EOPNOTSUPP;
...@@ -4028,18 +3967,20 @@ int bond_parse_parm(const char *buf, const struct bond_parm_tbl *tbl) ...@@ -4028,18 +3967,20 @@ int bond_parse_parm(const char *buf, const struct bond_parm_tbl *tbl)
static int bond_check_params(struct bond_params *params) static int bond_check_params(struct bond_params *params)
{ {
int arp_validate_value, fail_over_mac_value, primary_reselect_value, i; int arp_validate_value, fail_over_mac_value, primary_reselect_value, i;
struct bond_opt_value newval, *valptr;
int arp_all_targets_value; int arp_all_targets_value;
/* /*
* Convert string parameters. * Convert string parameters.
*/ */
if (mode) { if (mode) {
bond_mode = bond_parse_parm(mode, bond_mode_tbl); bond_opt_initstr(&newval, mode);
if (bond_mode == -1) { valptr = bond_opt_parse(bond_opt_get(BOND_OPT_MODE), &newval);
pr_err("Error: Invalid bonding mode \"%s\"\n", if (!valptr) {
mode == NULL ? "NULL" : mode); pr_err("Error: Invalid bonding mode \"%s\"\n", mode);
return -EINVAL; return -EINVAL;
} }
bond_mode = valptr->value;
} }
if (xmit_hash_policy) { if (xmit_hash_policy) {
...@@ -4048,14 +3989,15 @@ static int bond_check_params(struct bond_params *params) ...@@ -4048,14 +3989,15 @@ static int bond_check_params(struct bond_params *params)
pr_info("xmit_hash_policy param is irrelevant in mode %s\n", pr_info("xmit_hash_policy param is irrelevant in mode %s\n",
bond_mode_name(bond_mode)); bond_mode_name(bond_mode));
} else { } else {
xmit_hashtype = bond_parse_parm(xmit_hash_policy, bond_opt_initstr(&newval, xmit_hash_policy);
xmit_hashtype_tbl); valptr = bond_opt_parse(bond_opt_get(BOND_OPT_XMIT_HASH),
if (xmit_hashtype == -1) { &newval);
if (!valptr) {
pr_err("Error: Invalid xmit_hash_policy \"%s\"\n", pr_err("Error: Invalid xmit_hash_policy \"%s\"\n",
xmit_hash_policy == NULL ? "NULL" :
xmit_hash_policy); xmit_hash_policy);
return -EINVAL; return -EINVAL;
} }
xmit_hashtype = valptr->value;
} }
} }
...@@ -4064,26 +4006,29 @@ static int bond_check_params(struct bond_params *params) ...@@ -4064,26 +4006,29 @@ static int bond_check_params(struct bond_params *params)
pr_info("lacp_rate param is irrelevant in mode %s\n", pr_info("lacp_rate param is irrelevant in mode %s\n",
bond_mode_name(bond_mode)); bond_mode_name(bond_mode));
} else { } else {
lacp_fast = bond_parse_parm(lacp_rate, bond_lacp_tbl); bond_opt_initstr(&newval, lacp_rate);
if (lacp_fast == -1) { valptr = bond_opt_parse(bond_opt_get(BOND_OPT_LACP_RATE),
&newval);
if (!valptr) {
pr_err("Error: Invalid lacp rate \"%s\"\n", pr_err("Error: Invalid lacp rate \"%s\"\n",
lacp_rate == NULL ? "NULL" : lacp_rate); lacp_rate);
return -EINVAL; return -EINVAL;
} }
lacp_fast = valptr->value;
} }
} }
if (ad_select) { if (ad_select) {
params->ad_select = bond_parse_parm(ad_select, ad_select_tbl); bond_opt_initstr(&newval, lacp_rate);
if (params->ad_select == -1) { valptr = bond_opt_parse(bond_opt_get(BOND_OPT_AD_SELECT),
pr_err("Error: Invalid ad_select \"%s\"\n", &newval);
ad_select == NULL ? "NULL" : ad_select); if (!valptr) {
pr_err("Error: Invalid ad_select \"%s\"\n", ad_select);
return -EINVAL; return -EINVAL;
} }
params->ad_select = valptr->value;
if (bond_mode != BOND_MODE_8023AD) { if (bond_mode != BOND_MODE_8023AD)
pr_warning("ad_select param only affects 802.3ad mode\n"); pr_warning("ad_select param only affects 802.3ad mode\n");
}
} else { } else {
params->ad_select = BOND_AD_STABLE; params->ad_select = BOND_AD_STABLE;
} }
...@@ -4095,9 +4040,9 @@ static int bond_check_params(struct bond_params *params) ...@@ -4095,9 +4040,9 @@ static int bond_check_params(struct bond_params *params)
} }
if (miimon < 0) { if (miimon < 0) {
pr_warning("Warning: miimon module parameter (%d), not in range 0-%d, so it was reset to %d\n", pr_warning("Warning: miimon module parameter (%d), not in range 0-%d, so it was reset to 0\n",
miimon, INT_MAX, BOND_LINK_MON_INTERV); miimon, INT_MAX);
miimon = BOND_LINK_MON_INTERV; miimon = 0;
} }
if (updelay < 0) { if (updelay < 0) {
...@@ -4154,7 +4099,8 @@ static int bond_check_params(struct bond_params *params) ...@@ -4154,7 +4099,8 @@ static int bond_check_params(struct bond_params *params)
resend_igmp = BOND_DEFAULT_RESEND_IGMP; resend_igmp = BOND_DEFAULT_RESEND_IGMP;
} }
if (packets_per_slave < 0 || packets_per_slave > USHRT_MAX) { bond_opt_initval(&newval, packets_per_slave);
if (!bond_opt_parse(bond_opt_get(BOND_OPT_PACKETS_PER_SLAVE), &newval)) {
pr_warn("Warning: packets_per_slave (%d) should be between 0 and %u resetting to 1\n", pr_warn("Warning: packets_per_slave (%d) should be between 0 and %u resetting to 1\n",
packets_per_slave, USHRT_MAX); packets_per_slave, USHRT_MAX);
packets_per_slave = 1; packets_per_slave = 1;
...@@ -4199,9 +4145,9 @@ static int bond_check_params(struct bond_params *params) ...@@ -4199,9 +4145,9 @@ static int bond_check_params(struct bond_params *params)
} }
if (arp_interval < 0) { if (arp_interval < 0) {
pr_warning("Warning: arp_interval module parameter (%d) , not in range 0-%d, so it was reset to %d\n", pr_warning("Warning: arp_interval module parameter (%d) , not in range 0-%d, so it was reset to 0\n",
arp_interval, INT_MAX, BOND_LINK_ARP_INTERV); arp_interval, INT_MAX);
arp_interval = BOND_LINK_ARP_INTERV; arp_interval = 0;
} }
for (arp_ip_count = 0, i = 0; for (arp_ip_count = 0, i = 0;
...@@ -4240,35 +4186,40 @@ static int bond_check_params(struct bond_params *params) ...@@ -4240,35 +4186,40 @@ static int bond_check_params(struct bond_params *params)
return -EINVAL; return -EINVAL;
} }
arp_validate_value = bond_parse_parm(arp_validate, bond_opt_initstr(&newval, arp_validate);
arp_validate_tbl); valptr = bond_opt_parse(bond_opt_get(BOND_OPT_ARP_VALIDATE),
if (arp_validate_value == -1) { &newval);
if (!valptr) {
pr_err("Error: invalid arp_validate \"%s\"\n", pr_err("Error: invalid arp_validate \"%s\"\n",
arp_validate == NULL ? "NULL" : arp_validate); arp_validate);
return -EINVAL; return -EINVAL;
} }
} else arp_validate_value = valptr->value;
} else {
arp_validate_value = 0; arp_validate_value = 0;
}
arp_all_targets_value = 0; arp_all_targets_value = 0;
if (arp_all_targets) { if (arp_all_targets) {
arp_all_targets_value = bond_parse_parm(arp_all_targets, bond_opt_initstr(&newval, arp_all_targets);
arp_all_targets_tbl); valptr = bond_opt_parse(bond_opt_get(BOND_OPT_ARP_ALL_TARGETS),
&newval);
if (arp_all_targets_value == -1) { if (!valptr) {
pr_err("Error: invalid arp_all_targets_value \"%s\"\n", pr_err("Error: invalid arp_all_targets_value \"%s\"\n",
arp_all_targets); arp_all_targets);
arp_all_targets_value = 0; arp_all_targets_value = 0;
} else {
arp_all_targets_value = valptr->value;
} }
} }
if (miimon) { if (miimon) {
pr_info("MII link monitoring set to %d ms\n", miimon); pr_info("MII link monitoring set to %d ms\n", miimon);
} else if (arp_interval) { } else if (arp_interval) {
valptr = bond_opt_get_val(BOND_OPT_ARP_VALIDATE,
arp_validate_value);
pr_info("ARP monitoring set to %d ms, validate %s, with %d target(s):", pr_info("ARP monitoring set to %d ms, validate %s, with %d target(s):",
arp_interval, arp_interval, valptr->string, arp_ip_count);
arp_validate_tbl[arp_validate_value].modename,
arp_ip_count);
for (i = 0; i < arp_ip_count; i++) for (i = 0; i < arp_ip_count; i++)
pr_info(" %s", arp_ip_target[i]); pr_info(" %s", arp_ip_target[i]);
...@@ -4292,27 +4243,29 @@ static int bond_check_params(struct bond_params *params) ...@@ -4292,27 +4243,29 @@ static int bond_check_params(struct bond_params *params)
} }
if (primary && primary_reselect) { if (primary && primary_reselect) {
primary_reselect_value = bond_parse_parm(primary_reselect, bond_opt_initstr(&newval, primary_reselect);
pri_reselect_tbl); valptr = bond_opt_parse(bond_opt_get(BOND_OPT_PRIMARY_RESELECT),
if (primary_reselect_value == -1) { &newval);
if (!valptr) {
pr_err("Error: Invalid primary_reselect \"%s\"\n", pr_err("Error: Invalid primary_reselect \"%s\"\n",
primary_reselect == primary_reselect);
NULL ? "NULL" : primary_reselect);
return -EINVAL; return -EINVAL;
} }
primary_reselect_value = valptr->value;
} else { } else {
primary_reselect_value = BOND_PRI_RESELECT_ALWAYS; primary_reselect_value = BOND_PRI_RESELECT_ALWAYS;
} }
if (fail_over_mac) { if (fail_over_mac) {
fail_over_mac_value = bond_parse_parm(fail_over_mac, bond_opt_initstr(&newval, fail_over_mac);
fail_over_mac_tbl); valptr = bond_opt_parse(bond_opt_get(BOND_OPT_FAIL_OVER_MAC),
if (fail_over_mac_value == -1) { &newval);
if (!valptr) {
pr_err("Error: invalid fail_over_mac \"%s\"\n", pr_err("Error: invalid fail_over_mac \"%s\"\n",
arp_validate == NULL ? "NULL" : arp_validate); fail_over_mac);
return -EINVAL; return -EINVAL;
} }
fail_over_mac_value = valptr->value;
if (bond_mode != BOND_MODE_ACTIVEBACKUP) if (bond_mode != BOND_MODE_ACTIVEBACKUP)
pr_warning("Warning: fail_over_mac only affects active-backup mode.\n"); pr_warning("Warning: fail_over_mac only affects active-backup mode.\n");
} else { } else {
......
...@@ -98,6 +98,7 @@ static int bond_changelink(struct net_device *bond_dev, ...@@ -98,6 +98,7 @@ static int bond_changelink(struct net_device *bond_dev,
struct nlattr *tb[], struct nlattr *data[]) struct nlattr *tb[], struct nlattr *data[])
{ {
struct bonding *bond = netdev_priv(bond_dev); struct bonding *bond = netdev_priv(bond_dev);
struct bond_opt_value newval;
int miimon = 0; int miimon = 0;
int err; int err;
...@@ -107,51 +108,57 @@ static int bond_changelink(struct net_device *bond_dev, ...@@ -107,51 +108,57 @@ static int bond_changelink(struct net_device *bond_dev,
if (data[IFLA_BOND_MODE]) { if (data[IFLA_BOND_MODE]) {
int mode = nla_get_u8(data[IFLA_BOND_MODE]); int mode = nla_get_u8(data[IFLA_BOND_MODE]);
err = bond_option_mode_set(bond, mode); bond_opt_initval(&newval, mode);
err = __bond_opt_set(bond, BOND_OPT_MODE, &newval);
if (err) if (err)
return err; return err;
} }
if (data[IFLA_BOND_ACTIVE_SLAVE]) { if (data[IFLA_BOND_ACTIVE_SLAVE]) {
int ifindex = nla_get_u32(data[IFLA_BOND_ACTIVE_SLAVE]); int ifindex = nla_get_u32(data[IFLA_BOND_ACTIVE_SLAVE]);
struct net_device *slave_dev; struct net_device *slave_dev;
char *active_slave = "";
if (ifindex == 0) { if (ifindex != 0) {
slave_dev = NULL;
} else {
slave_dev = __dev_get_by_index(dev_net(bond_dev), slave_dev = __dev_get_by_index(dev_net(bond_dev),
ifindex); ifindex);
if (!slave_dev) if (!slave_dev)
return -ENODEV; return -ENODEV;
active_slave = slave_dev->name;
} }
err = bond_option_active_slave_set(bond, slave_dev); bond_opt_initstr(&newval, active_slave);
err = __bond_opt_set(bond, BOND_OPT_ACTIVE_SLAVE, &newval);
if (err) if (err)
return err; return err;
} }
if (data[IFLA_BOND_MIIMON]) { if (data[IFLA_BOND_MIIMON]) {
miimon = nla_get_u32(data[IFLA_BOND_MIIMON]); miimon = nla_get_u32(data[IFLA_BOND_MIIMON]);
err = bond_option_miimon_set(bond, miimon); bond_opt_initval(&newval, miimon);
err = __bond_opt_set(bond, BOND_OPT_MIIMON, &newval);
if (err) if (err)
return err; return err;
} }
if (data[IFLA_BOND_UPDELAY]) { if (data[IFLA_BOND_UPDELAY]) {
int updelay = nla_get_u32(data[IFLA_BOND_UPDELAY]); int updelay = nla_get_u32(data[IFLA_BOND_UPDELAY]);
err = bond_option_updelay_set(bond, updelay); bond_opt_initval(&newval, updelay);
err = __bond_opt_set(bond, BOND_OPT_UPDELAY, &newval);
if (err) if (err)
return err; return err;
} }
if (data[IFLA_BOND_DOWNDELAY]) { if (data[IFLA_BOND_DOWNDELAY]) {
int downdelay = nla_get_u32(data[IFLA_BOND_DOWNDELAY]); int downdelay = nla_get_u32(data[IFLA_BOND_DOWNDELAY]);
err = bond_option_downdelay_set(bond, downdelay); bond_opt_initval(&newval, downdelay);
err = __bond_opt_set(bond, BOND_OPT_DOWNDELAY, &newval);
if (err) if (err)
return err; return err;
} }
if (data[IFLA_BOND_USE_CARRIER]) { if (data[IFLA_BOND_USE_CARRIER]) {
int use_carrier = nla_get_u8(data[IFLA_BOND_USE_CARRIER]); int use_carrier = nla_get_u8(data[IFLA_BOND_USE_CARRIER]);
err = bond_option_use_carrier_set(bond, use_carrier); bond_opt_initval(&newval, use_carrier);
err = __bond_opt_set(bond, BOND_OPT_USE_CARRIER, &newval);
if (err) if (err)
return err; return err;
} }
...@@ -164,21 +171,29 @@ static int bond_changelink(struct net_device *bond_dev, ...@@ -164,21 +171,29 @@ static int bond_changelink(struct net_device *bond_dev,
return -EINVAL; return -EINVAL;
} }
err = bond_option_arp_interval_set(bond, arp_interval); bond_opt_initval(&newval, arp_interval);
err = __bond_opt_set(bond, BOND_OPT_ARP_INTERVAL, &newval);
if (err) if (err)
return err; return err;
} }
if (data[IFLA_BOND_ARP_IP_TARGET]) { if (data[IFLA_BOND_ARP_IP_TARGET]) {
__be32 targets[BOND_MAX_ARP_TARGETS] = { 0, };
struct nlattr *attr; struct nlattr *attr;
int i = 0, rem; int i = 0, rem;
bond_option_arp_ip_targets_clear(bond);
nla_for_each_nested(attr, data[IFLA_BOND_ARP_IP_TARGET], rem) { nla_for_each_nested(attr, data[IFLA_BOND_ARP_IP_TARGET], rem) {
__be32 target = nla_get_be32(attr); __be32 target = nla_get_be32(attr);
targets[i++] = target;
}
err = bond_option_arp_ip_targets_set(bond, targets, i); bond_opt_initval(&newval, target);
err = __bond_opt_set(bond, BOND_OPT_ARP_TARGETS,
&newval);
if (err)
break;
i++;
}
if (i == 0 && bond->params.arp_interval)
pr_warn("%s: removing last arp target with arp_interval on\n",
bond->dev->name);
if (err) if (err)
return err; return err;
} }
...@@ -191,7 +206,8 @@ static int bond_changelink(struct net_device *bond_dev, ...@@ -191,7 +206,8 @@ static int bond_changelink(struct net_device *bond_dev,
return -EINVAL; return -EINVAL;
} }
err = bond_option_arp_validate_set(bond, arp_validate); bond_opt_initval(&newval, arp_validate);
err = __bond_opt_set(bond, BOND_OPT_ARP_VALIDATE, &newval);
if (err) if (err)
return err; return err;
} }
...@@ -199,7 +215,8 @@ static int bond_changelink(struct net_device *bond_dev, ...@@ -199,7 +215,8 @@ static int bond_changelink(struct net_device *bond_dev,
int arp_all_targets = int arp_all_targets =
nla_get_u32(data[IFLA_BOND_ARP_ALL_TARGETS]); nla_get_u32(data[IFLA_BOND_ARP_ALL_TARGETS]);
err = bond_option_arp_all_targets_set(bond, arp_all_targets); bond_opt_initval(&newval, arp_all_targets);
err = __bond_opt_set(bond, BOND_OPT_ARP_ALL_TARGETS, &newval);
if (err) if (err)
return err; return err;
} }
...@@ -212,7 +229,8 @@ static int bond_changelink(struct net_device *bond_dev, ...@@ -212,7 +229,8 @@ static int bond_changelink(struct net_device *bond_dev,
if (dev) if (dev)
primary = dev->name; primary = dev->name;
err = bond_option_primary_set(bond, primary); bond_opt_initstr(&newval, primary);
err = __bond_opt_set(bond, BOND_OPT_PRIMARY, &newval);
if (err) if (err)
return err; return err;
} }
...@@ -220,7 +238,8 @@ static int bond_changelink(struct net_device *bond_dev, ...@@ -220,7 +238,8 @@ static int bond_changelink(struct net_device *bond_dev,
int primary_reselect = int primary_reselect =
nla_get_u8(data[IFLA_BOND_PRIMARY_RESELECT]); nla_get_u8(data[IFLA_BOND_PRIMARY_RESELECT]);
err = bond_option_primary_reselect_set(bond, primary_reselect); bond_opt_initval(&newval, primary_reselect);
err = __bond_opt_set(bond, BOND_OPT_PRIMARY_RESELECT, &newval);
if (err) if (err)
return err; return err;
} }
...@@ -228,7 +247,8 @@ static int bond_changelink(struct net_device *bond_dev, ...@@ -228,7 +247,8 @@ static int bond_changelink(struct net_device *bond_dev,
int fail_over_mac = int fail_over_mac =
nla_get_u8(data[IFLA_BOND_FAIL_OVER_MAC]); nla_get_u8(data[IFLA_BOND_FAIL_OVER_MAC]);
err = bond_option_fail_over_mac_set(bond, fail_over_mac); bond_opt_initval(&newval, fail_over_mac);
err = __bond_opt_set(bond, BOND_OPT_FAIL_OVER_MAC, &newval);
if (err) if (err)
return err; return err;
} }
...@@ -236,7 +256,8 @@ static int bond_changelink(struct net_device *bond_dev, ...@@ -236,7 +256,8 @@ static int bond_changelink(struct net_device *bond_dev,
int xmit_hash_policy = int xmit_hash_policy =
nla_get_u8(data[IFLA_BOND_XMIT_HASH_POLICY]); nla_get_u8(data[IFLA_BOND_XMIT_HASH_POLICY]);
err = bond_option_xmit_hash_policy_set(bond, xmit_hash_policy); bond_opt_initval(&newval, xmit_hash_policy);
err = __bond_opt_set(bond, BOND_OPT_XMIT_HASH, &newval);
if (err) if (err)
return err; return err;
} }
...@@ -244,7 +265,8 @@ static int bond_changelink(struct net_device *bond_dev, ...@@ -244,7 +265,8 @@ static int bond_changelink(struct net_device *bond_dev,
int resend_igmp = int resend_igmp =
nla_get_u32(data[IFLA_BOND_RESEND_IGMP]); nla_get_u32(data[IFLA_BOND_RESEND_IGMP]);
err = bond_option_resend_igmp_set(bond, resend_igmp); bond_opt_initval(&newval, resend_igmp);
err = __bond_opt_set(bond, BOND_OPT_RESEND_IGMP, &newval);
if (err) if (err)
return err; return err;
} }
...@@ -252,7 +274,8 @@ static int bond_changelink(struct net_device *bond_dev, ...@@ -252,7 +274,8 @@ static int bond_changelink(struct net_device *bond_dev,
int num_peer_notif = int num_peer_notif =
nla_get_u8(data[IFLA_BOND_NUM_PEER_NOTIF]); nla_get_u8(data[IFLA_BOND_NUM_PEER_NOTIF]);
err = bond_option_num_peer_notif_set(bond, num_peer_notif); bond_opt_initval(&newval, num_peer_notif);
err = __bond_opt_set(bond, BOND_OPT_NUM_PEER_NOTIF, &newval);
if (err) if (err)
return err; return err;
} }
...@@ -260,8 +283,8 @@ static int bond_changelink(struct net_device *bond_dev, ...@@ -260,8 +283,8 @@ static int bond_changelink(struct net_device *bond_dev,
int all_slaves_active = int all_slaves_active =
nla_get_u8(data[IFLA_BOND_ALL_SLAVES_ACTIVE]); nla_get_u8(data[IFLA_BOND_ALL_SLAVES_ACTIVE]);
err = bond_option_all_slaves_active_set(bond, bond_opt_initval(&newval, all_slaves_active);
all_slaves_active); err = __bond_opt_set(bond, BOND_OPT_ALL_SLAVES_ACTIVE, &newval);
if (err) if (err)
return err; return err;
} }
...@@ -269,7 +292,8 @@ static int bond_changelink(struct net_device *bond_dev, ...@@ -269,7 +292,8 @@ static int bond_changelink(struct net_device *bond_dev,
int min_links = int min_links =
nla_get_u32(data[IFLA_BOND_MIN_LINKS]); nla_get_u32(data[IFLA_BOND_MIN_LINKS]);
err = bond_option_min_links_set(bond, min_links); bond_opt_initval(&newval, min_links);
err = __bond_opt_set(bond, BOND_OPT_MINLINKS, &newval);
if (err) if (err)
return err; return err;
} }
...@@ -277,7 +301,8 @@ static int bond_changelink(struct net_device *bond_dev, ...@@ -277,7 +301,8 @@ static int bond_changelink(struct net_device *bond_dev,
int lp_interval = int lp_interval =
nla_get_u32(data[IFLA_BOND_LP_INTERVAL]); nla_get_u32(data[IFLA_BOND_LP_INTERVAL]);
err = bond_option_lp_interval_set(bond, lp_interval); bond_opt_initval(&newval, lp_interval);
err = __bond_opt_set(bond, BOND_OPT_LP_INTERVAL, &newval);
if (err) if (err)
return err; return err;
} }
...@@ -285,8 +310,8 @@ static int bond_changelink(struct net_device *bond_dev, ...@@ -285,8 +310,8 @@ static int bond_changelink(struct net_device *bond_dev,
int packets_per_slave = int packets_per_slave =
nla_get_u32(data[IFLA_BOND_PACKETS_PER_SLAVE]); nla_get_u32(data[IFLA_BOND_PACKETS_PER_SLAVE]);
err = bond_option_packets_per_slave_set(bond, bond_opt_initval(&newval, packets_per_slave);
packets_per_slave); err = __bond_opt_set(bond, BOND_OPT_PACKETS_PER_SLAVE, &newval);
if (err) if (err)
return err; return err;
} }
...@@ -294,7 +319,8 @@ static int bond_changelink(struct net_device *bond_dev, ...@@ -294,7 +319,8 @@ static int bond_changelink(struct net_device *bond_dev,
int lacp_rate = int lacp_rate =
nla_get_u8(data[IFLA_BOND_AD_LACP_RATE]); nla_get_u8(data[IFLA_BOND_AD_LACP_RATE]);
err = bond_option_lacp_rate_set(bond, lacp_rate); bond_opt_initval(&newval, lacp_rate);
err = __bond_opt_set(bond, BOND_OPT_LACP_RATE, &newval);
if (err) if (err)
return err; return err;
} }
...@@ -302,7 +328,8 @@ static int bond_changelink(struct net_device *bond_dev, ...@@ -302,7 +328,8 @@ static int bond_changelink(struct net_device *bond_dev,
int ad_select = int ad_select =
nla_get_u8(data[IFLA_BOND_AD_SELECT]); nla_get_u8(data[IFLA_BOND_AD_SELECT]);
err = bond_option_ad_select_set(bond, ad_select); bond_opt_initval(&newval, ad_select);
err = __bond_opt_set(bond, BOND_OPT_AD_SELECT, &newval);
if (err) if (err)
return err; return err;
} }
......
...@@ -16,31 +16,575 @@ ...@@ -16,31 +16,575 @@
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/rwlock.h> #include <linux/rwlock.h>
#include <linux/rcupdate.h> #include <linux/rcupdate.h>
#include <linux/ctype.h>
#include <linux/inet.h>
#include "bonding.h" #include "bonding.h"
int bond_option_mode_set(struct bonding *bond, int mode) static struct bond_opt_value bond_mode_tbl[] = {
{ "balance-rr", BOND_MODE_ROUNDROBIN, BOND_VALFLAG_DEFAULT},
{ "active-backup", BOND_MODE_ACTIVEBACKUP, 0},
{ "balance-xor", BOND_MODE_XOR, 0},
{ "broadcast", BOND_MODE_BROADCAST, 0},
{ "802.3ad", BOND_MODE_8023AD, 0},
{ "balance-tlb", BOND_MODE_TLB, 0},
{ "balance-alb", BOND_MODE_ALB, 0},
{ NULL, -1, 0},
};
static struct bond_opt_value bond_pps_tbl[] = {
{ "default", 1, BOND_VALFLAG_DEFAULT},
{ "maxval", USHRT_MAX, BOND_VALFLAG_MAX},
{ NULL, -1, 0},
};
static struct bond_opt_value bond_xmit_hashtype_tbl[] = {
{ "layer2", BOND_XMIT_POLICY_LAYER2, BOND_VALFLAG_DEFAULT},
{ "layer3+4", BOND_XMIT_POLICY_LAYER34, 0},
{ "layer2+3", BOND_XMIT_POLICY_LAYER23, 0},
{ "encap2+3", BOND_XMIT_POLICY_ENCAP23, 0},
{ "encap3+4", BOND_XMIT_POLICY_ENCAP34, 0},
{ NULL, -1, 0},
};
static struct bond_opt_value bond_arp_validate_tbl[] = {
{ "none", BOND_ARP_VALIDATE_NONE, BOND_VALFLAG_DEFAULT},
{ "active", BOND_ARP_VALIDATE_ACTIVE, 0},
{ "backup", BOND_ARP_VALIDATE_BACKUP, 0},
{ "all", BOND_ARP_VALIDATE_ALL, 0},
{ NULL, -1, 0},
};
static struct bond_opt_value bond_arp_all_targets_tbl[] = {
{ "any", BOND_ARP_TARGETS_ANY, BOND_VALFLAG_DEFAULT},
{ "all", BOND_ARP_TARGETS_ALL, 0},
{ NULL, -1, 0},
};
static struct bond_opt_value bond_fail_over_mac_tbl[] = {
{ "none", BOND_FOM_NONE, BOND_VALFLAG_DEFAULT},
{ "active", BOND_FOM_ACTIVE, 0},
{ "follow", BOND_FOM_FOLLOW, 0},
{ NULL, -1, 0},
};
static struct bond_opt_value bond_intmax_tbl[] = {
{ "off", 0, BOND_VALFLAG_DEFAULT},
{ "maxval", INT_MAX, BOND_VALFLAG_MAX},
};
static struct bond_opt_value bond_lacp_rate_tbl[] = {
{ "slow", AD_LACP_SLOW, 0},
{ "fast", AD_LACP_FAST, 0},
{ NULL, -1, 0},
};
static struct bond_opt_value bond_ad_select_tbl[] = {
{ "stable", BOND_AD_STABLE, BOND_VALFLAG_DEFAULT},
{ "bandwidth", BOND_AD_BANDWIDTH, 0},
{ "count", BOND_AD_COUNT, 0},
{ NULL, -1, 0},
};
static struct bond_opt_value bond_num_peer_notif_tbl[] = {
{ "off", 0, 0},
{ "maxval", 255, BOND_VALFLAG_MAX},
{ "default", 1, BOND_VALFLAG_DEFAULT},
{ NULL, -1, 0}
};
static struct bond_opt_value bond_primary_reselect_tbl[] = {
{ "always", BOND_PRI_RESELECT_ALWAYS, BOND_VALFLAG_DEFAULT},
{ "better", BOND_PRI_RESELECT_BETTER, 0},
{ "failure", BOND_PRI_RESELECT_FAILURE, 0},
{ NULL, -1},
};
static struct bond_opt_value bond_use_carrier_tbl[] = {
{ "off", 0, 0},
{ "on", 1, BOND_VALFLAG_DEFAULT},
{ NULL, -1, 0}
};
static struct bond_opt_value bond_all_slaves_active_tbl[] = {
{ "off", 0, BOND_VALFLAG_DEFAULT},
{ "on", 1, 0},
{ NULL, -1, 0}
};
static struct bond_opt_value bond_resend_igmp_tbl[] = {
{ "off", 0, 0},
{ "maxval", 255, BOND_VALFLAG_MAX},
{ "default", 1, BOND_VALFLAG_DEFAULT},
{ NULL, -1, 0}
};
static struct bond_opt_value bond_lp_interval_tbl[] = {
{ "minval", 1, BOND_VALFLAG_MIN | BOND_VALFLAG_DEFAULT},
{ "maxval", INT_MAX, BOND_VALFLAG_MAX},
};
static struct bond_option bond_opts[] = {
[BOND_OPT_MODE] = {
.id = BOND_OPT_MODE,
.name = "mode",
.desc = "bond device mode",
.flags = BOND_OPTFLAG_NOSLAVES | BOND_OPTFLAG_IFDOWN,
.values = bond_mode_tbl,
.set = bond_option_mode_set
},
[BOND_OPT_PACKETS_PER_SLAVE] = {
.id = BOND_OPT_PACKETS_PER_SLAVE,
.name = "packets_per_slave",
.desc = "Packets to send per slave in RR mode",
.unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_ROUNDROBIN)),
.values = bond_pps_tbl,
.set = bond_option_pps_set
},
[BOND_OPT_XMIT_HASH] = {
.id = BOND_OPT_XMIT_HASH,
.name = "xmit_hash_policy",
.desc = "balance-xor and 802.3ad hashing method",
.values = bond_xmit_hashtype_tbl,
.set = bond_option_xmit_hash_policy_set
},
[BOND_OPT_ARP_VALIDATE] = {
.id = BOND_OPT_ARP_VALIDATE,
.name = "arp_validate",
.desc = "validate src/dst of ARP probes",
.unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_ACTIVEBACKUP)),
.values = bond_arp_validate_tbl,
.set = bond_option_arp_validate_set
},
[BOND_OPT_ARP_ALL_TARGETS] = {
.id = BOND_OPT_ARP_ALL_TARGETS,
.name = "arp_all_targets",
.desc = "fail on any/all arp targets timeout",
.values = bond_arp_all_targets_tbl,
.set = bond_option_arp_all_targets_set
},
[BOND_OPT_FAIL_OVER_MAC] = {
.id = BOND_OPT_FAIL_OVER_MAC,
.name = "fail_over_mac",
.desc = "For active-backup, do not set all slaves to the same MAC",
.flags = BOND_OPTFLAG_NOSLAVES,
.values = bond_fail_over_mac_tbl,
.set = bond_option_fail_over_mac_set
},
[BOND_OPT_ARP_INTERVAL] = {
.id = BOND_OPT_ARP_INTERVAL,
.name = "arp_interval",
.desc = "arp interval in milliseconds",
.unsuppmodes = BIT(BOND_MODE_8023AD) | BIT(BOND_MODE_TLB) |
BIT(BOND_MODE_ALB),
.values = bond_intmax_tbl,
.set = bond_option_arp_interval_set
},
[BOND_OPT_ARP_TARGETS] = {
.id = BOND_OPT_ARP_TARGETS,
.name = "arp_ip_target",
.desc = "arp targets in n.n.n.n form",
.flags = BOND_OPTFLAG_RAWVAL,
.set = bond_option_arp_ip_targets_set
},
[BOND_OPT_DOWNDELAY] = {
.id = BOND_OPT_DOWNDELAY,
.name = "downdelay",
.desc = "Delay before considering link down, in milliseconds",
.values = bond_intmax_tbl,
.set = bond_option_downdelay_set
},
[BOND_OPT_UPDELAY] = {
.id = BOND_OPT_UPDELAY,
.name = "updelay",
.desc = "Delay before considering link up, in milliseconds",
.values = bond_intmax_tbl,
.set = bond_option_updelay_set
},
[BOND_OPT_LACP_RATE] = {
.id = BOND_OPT_LACP_RATE,
.name = "lacp_rate",
.desc = "LACPDU tx rate to request from 802.3ad partner",
.flags = BOND_OPTFLAG_IFDOWN,
.unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_8023AD)),
.values = bond_lacp_rate_tbl,
.set = bond_option_lacp_rate_set
},
[BOND_OPT_MINLINKS] = {
.id = BOND_OPT_MINLINKS,
.name = "min_links",
.desc = "Minimum number of available links before turning on carrier",
.values = bond_intmax_tbl,
.set = bond_option_min_links_set
},
[BOND_OPT_AD_SELECT] = {
.id = BOND_OPT_AD_SELECT,
.name = "ad_select",
.desc = "803.ad aggregation selection logic",
.flags = BOND_OPTFLAG_IFDOWN,
.values = bond_ad_select_tbl,
.set = bond_option_ad_select_set
},
[BOND_OPT_NUM_PEER_NOTIF] = {
.id = BOND_OPT_NUM_PEER_NOTIF,
.name = "num_unsol_na",
.desc = "Number of peer notifications to send on failover event",
.values = bond_num_peer_notif_tbl,
.set = bond_option_num_peer_notif_set
},
[BOND_OPT_MIIMON] = {
.id = BOND_OPT_MIIMON,
.name = "miimon",
.desc = "Link check interval in milliseconds",
.values = bond_intmax_tbl,
.set = bond_option_miimon_set
},
[BOND_OPT_PRIMARY] = {
.id = BOND_OPT_PRIMARY,
.name = "primary",
.desc = "Primary network device to use",
.flags = BOND_OPTFLAG_RAWVAL,
.unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_ACTIVEBACKUP) |
BIT(BOND_MODE_TLB) |
BIT(BOND_MODE_ALB)),
.set = bond_option_primary_set
},
[BOND_OPT_PRIMARY_RESELECT] = {
.id = BOND_OPT_PRIMARY_RESELECT,
.name = "primary_reselect",
.desc = "Reselect primary slave once it comes up",
.values = bond_primary_reselect_tbl,
.set = bond_option_primary_reselect_set
},
[BOND_OPT_USE_CARRIER] = {
.id = BOND_OPT_USE_CARRIER,
.name = "use_carrier",
.desc = "Use netif_carrier_ok (vs MII ioctls) in miimon",
.values = bond_use_carrier_tbl,
.set = bond_option_use_carrier_set
},
[BOND_OPT_ACTIVE_SLAVE] = {
.id = BOND_OPT_ACTIVE_SLAVE,
.name = "active_slave",
.desc = "Currently active slave",
.flags = BOND_OPTFLAG_RAWVAL,
.unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_ACTIVEBACKUP) |
BIT(BOND_MODE_TLB) |
BIT(BOND_MODE_ALB)),
.set = bond_option_active_slave_set
},
[BOND_OPT_QUEUE_ID] = {
.id = BOND_OPT_QUEUE_ID,
.name = "queue_id",
.desc = "Set queue id of a slave",
.flags = BOND_OPTFLAG_RAWVAL,
.set = bond_option_queue_id_set
},
[BOND_OPT_ALL_SLAVES_ACTIVE] = {
.id = BOND_OPT_ALL_SLAVES_ACTIVE,
.name = "all_slaves_active",
.desc = "Keep all frames received on an interface by setting active flag for all slaves",
.values = bond_all_slaves_active_tbl,
.set = bond_option_all_slaves_active_set
},
[BOND_OPT_RESEND_IGMP] = {
.id = BOND_OPT_RESEND_IGMP,
.name = "resend_igmp",
.desc = "Number of IGMP membership reports to send on link failure",
.values = bond_resend_igmp_tbl,
.set = bond_option_resend_igmp_set
},
[BOND_OPT_LP_INTERVAL] = {
.id = BOND_OPT_LP_INTERVAL,
.name = "lp_interval",
.desc = "The number of seconds between instances where the bonding driver sends learning packets to each slave's peer switch",
.values = bond_lp_interval_tbl,
.set = bond_option_lp_interval_set
},
[BOND_OPT_SLAVES] = {
.id = BOND_OPT_SLAVES,
.name = "slaves",
.desc = "Slave membership management",
.flags = BOND_OPTFLAG_RAWVAL,
.set = bond_option_slaves_set
},
{ }
};
/* Searches for a value in opt's values[] table */
struct bond_opt_value *bond_opt_get_val(unsigned int option, u64 val)
{ {
if (bond_parm_tbl_lookup(mode, bond_mode_tbl) < 0) { struct bond_option *opt;
pr_err("%s: Ignoring invalid mode value %d.\n", int i;
bond->dev->name, mode);
return -EINVAL; opt = bond_opt_get(option);
if (WARN_ON(!opt))
return NULL;
for (i = 0; opt->values && opt->values[i].string; i++)
if (opt->values[i].value == val)
return &opt->values[i];
return NULL;
}
/* Searches for a value in opt's values[] table which matches the flagmask */
static struct bond_opt_value *bond_opt_get_flags(const struct bond_option *opt,
u32 flagmask)
{
int i;
for (i = 0; opt->values && opt->values[i].string; i++)
if (opt->values[i].flags & flagmask)
return &opt->values[i];
return NULL;
}
/* If maxval is missing then there's no range to check. In case minval is
* missing then it's considered to be 0.
*/
static bool bond_opt_check_range(const struct bond_option *opt, u64 val)
{
struct bond_opt_value *minval, *maxval;
minval = bond_opt_get_flags(opt, BOND_VALFLAG_MIN);
maxval = bond_opt_get_flags(opt, BOND_VALFLAG_MAX);
if (!maxval || (minval && val < minval->value) || val > maxval->value)
return false;
return true;
}
/**
* bond_opt_parse - parse option value
* @opt: the option to parse against
* @val: value to parse
*
* This function tries to extract the value from @val and check if it's
* a possible match for the option and returns NULL if a match isn't found,
* or the struct_opt_value that matched. It also strips the new line from
* @val->string if it's present.
*/
struct bond_opt_value *bond_opt_parse(const struct bond_option *opt,
struct bond_opt_value *val)
{
char *p, valstr[BOND_OPT_MAX_NAMELEN + 1] = { 0, };
struct bond_opt_value *tbl, *ret = NULL;
bool checkval;
int i, rv;
/* No parsing if the option wants a raw val */
if (opt->flags & BOND_OPTFLAG_RAWVAL)
return val;
tbl = opt->values;
if (!tbl)
goto out;
/* ULLONG_MAX is used to bypass string processing */
checkval = val->value != ULLONG_MAX;
if (!checkval) {
if (!val->string)
goto out;
p = strchr(val->string, '\n');
if (p)
*p = '\0';
for (p = val->string; *p; p++)
if (!(isdigit(*p) || isspace(*p)))
break;
/* The following code extracts the string to match or the value
* and sets checkval appropriately
*/
if (*p) {
rv = sscanf(val->string, "%32s", valstr);
} else {
rv = sscanf(val->string, "%llu", &val->value);
checkval = true;
}
if (!rv)
goto out;
} }
if (bond->dev->flags & IFF_UP) { for (i = 0; tbl[i].string; i++) {
pr_err("%s: unable to update mode because interface is up.\n", /* Check for exact match */
bond->dev->name); if (checkval) {
return -EPERM; if (val->value == tbl[i].value)
ret = &tbl[i];
} else {
if (!strcmp(valstr, "default") &&
(tbl[i].flags & BOND_VALFLAG_DEFAULT))
ret = &tbl[i];
if (!strcmp(valstr, tbl[i].string))
ret = &tbl[i];
} }
/* Found an exact match */
if (ret)
goto out;
}
/* Possible range match */
if (checkval && bond_opt_check_range(opt, val->value))
ret = val;
out:
return ret;
}
if (bond_has_slaves(bond)) { /* Check opt's dependencies against bond mode and currently set options */
pr_err("%s: unable to update mode because bond has slaves.\n", static int bond_opt_check_deps(struct bonding *bond,
bond->dev->name); const struct bond_option *opt)
return -EPERM; {
struct bond_params *params = &bond->params;
if (test_bit(params->mode, &opt->unsuppmodes))
return -EACCES;
if ((opt->flags & BOND_OPTFLAG_NOSLAVES) && bond_has_slaves(bond))
return -ENOTEMPTY;
if ((opt->flags & BOND_OPTFLAG_IFDOWN) && (bond->dev->flags & IFF_UP))
return -EBUSY;
return 0;
}
static void bond_opt_dep_print(struct bonding *bond,
const struct bond_option *opt)
{
struct bond_opt_value *modeval;
struct bond_params *params;
params = &bond->params;
modeval = bond_opt_get_val(BOND_OPT_MODE, params->mode);
if (test_bit(params->mode, &opt->unsuppmodes))
pr_err("%s: option %s: mode dependency failed, not supported in mode %s(%llu)\n",
bond->dev->name, opt->name,
modeval->string, modeval->value);
}
static void bond_opt_error_interpret(struct bonding *bond,
const struct bond_option *opt,
int error, struct bond_opt_value *val)
{
struct bond_opt_value *minval, *maxval;
char *p;
switch (error) {
case -EINVAL:
if (val) {
if (val->string) {
/* sometimes RAWVAL opts may have new lines */
p = strchr(val->string, '\n');
if (p)
*p = '\0';
pr_err("%s: option %s: invalid value (%s).\n",
bond->dev->name, opt->name, val->string);
} else {
pr_err("%s: option %s: invalid value (%llu).\n",
bond->dev->name, opt->name, val->value);
}
} }
minval = bond_opt_get_flags(opt, BOND_VALFLAG_MIN);
maxval = bond_opt_get_flags(opt, BOND_VALFLAG_MAX);
if (!maxval)
break;
pr_err("%s: option %s: allowed values %llu - %llu.\n",
bond->dev->name, opt->name, minval ? minval->value : 0,
maxval->value);
break;
case -EACCES:
bond_opt_dep_print(bond, opt);
break;
case -ENOTEMPTY:
pr_err("%s: option %s: unable to set because the bond device has slaves.\n",
bond->dev->name, opt->name);
break;
case -EBUSY:
pr_err("%s: option %s: unable to set because the bond device is up.\n",
bond->dev->name, opt->name);
break;
default:
break;
}
}
/**
* __bond_opt_set - set a bonding option
* @bond: target bond device
* @option: option to set
* @val: value to set it to
*
* This function is used to change the bond's option value, it can be
* used for both enabling/changing an option and for disabling it. RTNL lock
* must be obtained before calling this function.
*/
int __bond_opt_set(struct bonding *bond,
unsigned int option, struct bond_opt_value *val)
{
struct bond_opt_value *retval = NULL;
const struct bond_option *opt;
int ret = -ENOENT;
ASSERT_RTNL();
opt = bond_opt_get(option);
if (WARN_ON(!val) || WARN_ON(!opt))
goto out;
ret = bond_opt_check_deps(bond, opt);
if (ret)
goto out;
retval = bond_opt_parse(opt, val);
if (!retval) {
ret = -EINVAL;
goto out;
}
ret = opt->set(bond, retval);
out:
if (ret)
bond_opt_error_interpret(bond, opt, ret, val);
return ret;
}
/**
* bond_opt_tryset_rtnl - try to acquire rtnl and call __bond_opt_set
* @bond: target bond device
* @option: option to set
* @buf: value to set it to
*
* This function tries to acquire RTNL without blocking and if successful
* calls __bond_opt_set. It is mainly used for sysfs option manipulation.
*/
int bond_opt_tryset_rtnl(struct bonding *bond, unsigned int option, char *buf)
{
struct bond_opt_value optval;
int ret;
if (!rtnl_trylock())
return restart_syscall();
bond_opt_initstr(&optval, buf);
ret = __bond_opt_set(bond, option, &optval);
rtnl_unlock();
return ret;
}
if (BOND_NO_USES_ARP(mode) && bond->params.arp_interval) { /**
* bond_opt_get - get a pointer to an option
* @option: option for which to return a pointer
*
* This function checks if option is valid and if so returns a pointer
* to its entry in the bond_opts[] option array.
*/
struct bond_option *bond_opt_get(unsigned int option)
{
if (!BOND_OPT_VALID(option))
return NULL;
return &bond_opts[option];
}
int bond_option_mode_set(struct bonding *bond, struct bond_opt_value *newval)
{
if (BOND_NO_USES_ARP(newval->value) && bond->params.arp_interval) {
pr_info("%s: %s mode is incompatible with arp monitoring, start mii monitoring\n", pr_info("%s: %s mode is incompatible with arp monitoring, start mii monitoring\n",
bond->dev->name, bond_mode_tbl[mode].modename); bond->dev->name, newval->string);
/* disable arp monitoring */ /* disable arp monitoring */
bond->params.arp_interval = 0; bond->params.arp_interval = 0;
/* set miimon to default value */ /* set miimon to default value */
...@@ -51,7 +595,8 @@ int bond_option_mode_set(struct bonding *bond, int mode) ...@@ -51,7 +595,8 @@ int bond_option_mode_set(struct bonding *bond, int mode)
/* don't cache arp_validate between modes */ /* don't cache arp_validate between modes */
bond->params.arp_validate = BOND_ARP_VALIDATE_NONE; bond->params.arp_validate = BOND_ARP_VALIDATE_NONE;
bond->params.mode = mode; bond->params.mode = newval->value;
return 0; return 0;
} }
...@@ -74,10 +619,21 @@ struct net_device *bond_option_active_slave_get(struct bonding *bond) ...@@ -74,10 +619,21 @@ struct net_device *bond_option_active_slave_get(struct bonding *bond)
} }
int bond_option_active_slave_set(struct bonding *bond, int bond_option_active_slave_set(struct bonding *bond,
struct net_device *slave_dev) struct bond_opt_value *newval)
{ {
char ifname[IFNAMSIZ] = { 0, };
struct net_device *slave_dev;
int ret = 0; int ret = 0;
sscanf(newval->string, "%15s", ifname); /* IFNAMSIZ */
if (!strlen(ifname) || newval->string[0] == '\n') {
slave_dev = NULL;
} else {
slave_dev = __dev_get_by_name(dev_net(bond->dev), ifname);
if (!slave_dev)
return -ENODEV;
}
if (slave_dev) { if (slave_dev) {
if (!netif_is_bond_slave(slave_dev)) { if (!netif_is_bond_slave(slave_dev)) {
pr_err("Device %s is not bonding slave.\n", pr_err("Device %s is not bonding slave.\n",
...@@ -92,12 +648,6 @@ int bond_option_active_slave_set(struct bonding *bond, ...@@ -92,12 +648,6 @@ int bond_option_active_slave_set(struct bonding *bond,
} }
} }
if (!USES_PRIMARY(bond->params.mode)) {
pr_err("%s: Unable to change active slave; %s is in mode %d\n",
bond->dev->name, bond->dev->name, bond->params.mode);
return -EINVAL;
}
block_netpoll_tx(); block_netpoll_tx();
write_lock_bh(&bond->curr_slave_lock); write_lock_bh(&bond->curr_slave_lock);
...@@ -134,19 +684,15 @@ int bond_option_active_slave_set(struct bonding *bond, ...@@ -134,19 +684,15 @@ int bond_option_active_slave_set(struct bonding *bond,
write_unlock_bh(&bond->curr_slave_lock); write_unlock_bh(&bond->curr_slave_lock);
unblock_netpoll_tx(); unblock_netpoll_tx();
return ret; return ret;
} }
int bond_option_miimon_set(struct bonding *bond, int miimon) int bond_option_miimon_set(struct bonding *bond, struct bond_opt_value *newval)
{ {
if (miimon < 0) { pr_info("%s: Setting MII monitoring interval to %llu.\n",
pr_err("%s: Invalid miimon value %d not in range %d-%d; rejected.\n", bond->dev->name, newval->value);
bond->dev->name, miimon, 0, INT_MAX); bond->params.miimon = newval->value;
return -EINVAL;
}
pr_info("%s: Setting MII monitoring interval to %d.\n",
bond->dev->name, miimon);
bond->params.miimon = miimon;
if (bond->params.updelay) if (bond->params.updelay)
pr_info("%s: Note: Updating updelay (to %d) since it is a multiple of the miimon value.\n", pr_info("%s: Note: Updating updelay (to %d) since it is a multiple of the miimon value.\n",
bond->dev->name, bond->dev->name,
...@@ -155,7 +701,7 @@ int bond_option_miimon_set(struct bonding *bond, int miimon) ...@@ -155,7 +701,7 @@ int bond_option_miimon_set(struct bonding *bond, int miimon)
pr_info("%s: Note: Updating downdelay (to %d) since it is a multiple of the miimon value.\n", pr_info("%s: Note: Updating downdelay (to %d) since it is a multiple of the miimon value.\n",
bond->dev->name, bond->dev->name,
bond->params.downdelay * bond->params.miimon); bond->params.downdelay * bond->params.miimon);
if (miimon && bond->params.arp_interval) { if (newval->value && bond->params.arp_interval) {
pr_info("%s: MII monitoring cannot be used with ARP monitoring. Disabling ARP monitoring...\n", pr_info("%s: MII monitoring cannot be used with ARP monitoring. Disabling ARP monitoring...\n",
bond->dev->name); bond->dev->name);
bond->params.arp_interval = 0; bond->params.arp_interval = 0;
...@@ -168,104 +714,79 @@ int bond_option_miimon_set(struct bonding *bond, int miimon) ...@@ -168,104 +714,79 @@ int bond_option_miimon_set(struct bonding *bond, int miimon)
* timer will get fired off when the open function * timer will get fired off when the open function
* is called. * is called.
*/ */
if (!miimon) { if (!newval->value) {
cancel_delayed_work_sync(&bond->mii_work); cancel_delayed_work_sync(&bond->mii_work);
} else { } else {
cancel_delayed_work_sync(&bond->arp_work); cancel_delayed_work_sync(&bond->arp_work);
queue_delayed_work(bond->wq, &bond->mii_work, 0); queue_delayed_work(bond->wq, &bond->mii_work, 0);
} }
} }
return 0; return 0;
} }
int bond_option_updelay_set(struct bonding *bond, int updelay) int bond_option_updelay_set(struct bonding *bond, struct bond_opt_value *newval)
{ {
if (!(bond->params.miimon)) { if (!bond->params.miimon) {
pr_err("%s: Unable to set up delay as MII monitoring is disabled\n", pr_err("%s: Unable to set up delay as MII monitoring is disabled\n",
bond->dev->name); bond->dev->name);
return -EPERM; return -EPERM;
} }
if ((newval->value % bond->params.miimon) != 0) {
if (updelay < 0) { pr_warn("%s: Warning: up delay (%llu) is not a multiple of miimon (%d), updelay rounded to %llu ms\n",
pr_err("%s: Invalid up delay value %d not in range %d-%d; rejected.\n", bond->dev->name, newval->value,
bond->dev->name, updelay, 0, INT_MAX);
return -EINVAL;
} else {
if ((updelay % bond->params.miimon) != 0) {
pr_warn("%s: Warning: up delay (%d) is not a multiple of miimon (%d), updelay rounded to %d ms\n",
bond->dev->name, updelay,
bond->params.miimon, bond->params.miimon,
(updelay / bond->params.miimon) * (newval->value / bond->params.miimon) *
bond->params.miimon); bond->params.miimon);
} }
bond->params.updelay = updelay / bond->params.miimon; bond->params.updelay = newval->value / bond->params.miimon;
pr_info("%s: Setting up delay to %d.\n", pr_info("%s: Setting up delay to %d.\n",
bond->dev->name, bond->dev->name,
bond->params.updelay * bond->params.miimon); bond->params.updelay * bond->params.miimon);
}
return 0; return 0;
} }
int bond_option_downdelay_set(struct bonding *bond, int downdelay) int bond_option_downdelay_set(struct bonding *bond,
struct bond_opt_value *newval)
{ {
if (!(bond->params.miimon)) { if (!bond->params.miimon) {
pr_err("%s: Unable to set down delay as MII monitoring is disabled\n", pr_err("%s: Unable to set down delay as MII monitoring is disabled\n",
bond->dev->name); bond->dev->name);
return -EPERM; return -EPERM;
} }
if ((newval->value % bond->params.miimon) != 0) {
if (downdelay < 0) { pr_warn("%s: Warning: down delay (%llu) is not a multiple of miimon (%d), delay rounded to %llu ms\n",
pr_err("%s: Invalid down delay value %d not in range %d-%d; rejected.\n", bond->dev->name, newval->value,
bond->dev->name, downdelay, 0, INT_MAX);
return -EINVAL;
} else {
if ((downdelay % bond->params.miimon) != 0) {
pr_warn("%s: Warning: down delay (%d) is not a multiple of miimon (%d), delay rounded to %d ms\n",
bond->dev->name, downdelay,
bond->params.miimon, bond->params.miimon,
(downdelay / bond->params.miimon) * (newval->value / bond->params.miimon) *
bond->params.miimon); bond->params.miimon);
} }
bond->params.downdelay = downdelay / bond->params.miimon; bond->params.downdelay = newval->value / bond->params.miimon;
pr_info("%s: Setting down delay to %d.\n", pr_info("%s: Setting down delay to %d.\n",
bond->dev->name, bond->dev->name,
bond->params.downdelay * bond->params.miimon); bond->params.downdelay * bond->params.miimon);
}
return 0; return 0;
} }
int bond_option_use_carrier_set(struct bonding *bond, int use_carrier) int bond_option_use_carrier_set(struct bonding *bond,
struct bond_opt_value *newval)
{ {
if ((use_carrier == 0) || (use_carrier == 1)) { pr_info("%s: Setting use_carrier to %llu.\n",
bond->params.use_carrier = use_carrier; bond->dev->name, newval->value);
pr_info("%s: Setting use_carrier to %d.\n", bond->params.use_carrier = newval->value;
bond->dev->name, use_carrier);
} else {
pr_info("%s: Ignoring invalid use_carrier value %d.\n",
bond->dev->name, use_carrier);
}
return 0; return 0;
} }
int bond_option_arp_interval_set(struct bonding *bond, int arp_interval) int bond_option_arp_interval_set(struct bonding *bond,
struct bond_opt_value *newval)
{ {
if (arp_interval < 0) { pr_info("%s: Setting ARP monitoring interval to %llu.\n",
pr_err("%s: Invalid arp_interval value %d not in range 0-%d; rejected.\n", bond->dev->name, newval->value);
bond->dev->name, arp_interval, INT_MAX); bond->params.arp_interval = newval->value;
return -EINVAL; if (newval->value) {
}
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);
return -EINVAL;
}
pr_info("%s: Setting ARP monitoring interval to %d.\n",
bond->dev->name, arp_interval);
bond->params.arp_interval = arp_interval;
if (arp_interval) {
if (bond->params.miimon) { if (bond->params.miimon) {
pr_info("%s: ARP monitoring cannot be used with MII monitoring. %s Disabling MII monitoring.\n", pr_info("%s: ARP monitoring cannot be used with MII monitoring. %s Disabling MII monitoring.\n",
bond->dev->name, bond->dev->name); bond->dev->name, bond->dev->name);
...@@ -281,7 +802,7 @@ int bond_option_arp_interval_set(struct bonding *bond, int arp_interval) ...@@ -281,7 +802,7 @@ int bond_option_arp_interval_set(struct bonding *bond, int arp_interval)
* timer will get fired off when the open function * timer will get fired off when the open function
* is called. * is called.
*/ */
if (!arp_interval) { if (!newval->value) {
if (bond->params.arp_validate) if (bond->params.arp_validate)
bond->recv_probe = NULL; bond->recv_probe = NULL;
cancel_delayed_work_sync(&bond->arp_work); cancel_delayed_work_sync(&bond->arp_work);
...@@ -401,95 +922,84 @@ int bond_option_arp_ip_target_rem(struct bonding *bond, __be32 target) ...@@ -401,95 +922,84 @@ int bond_option_arp_ip_target_rem(struct bonding *bond, __be32 target)
return 0; return 0;
} }
int bond_option_arp_ip_targets_set(struct bonding *bond, __be32 *targets, void bond_option_arp_ip_targets_clear(struct bonding *bond)
int count)
{ {
int i, ret = 0; int i;
/* not to race with bond_arp_rcv */ /* not to race with bond_arp_rcv */
write_lock_bh(&bond->lock); write_lock_bh(&bond->lock);
/* clear table */
for (i = 0; i < BOND_MAX_ARP_TARGETS; i++) for (i = 0; i < BOND_MAX_ARP_TARGETS; i++)
_bond_options_arp_ip_target_set(bond, i, 0, 0); _bond_options_arp_ip_target_set(bond, i, 0, 0);
if (count == 0 && bond->params.arp_interval)
pr_warn("%s: removing last arp target with arp_interval on\n",
bond->dev->name);
for (i = 0; i < count; i++) {
ret = _bond_option_arp_ip_target_add(bond, targets[i]);
if (ret)
break;
}
write_unlock_bh(&bond->lock); write_unlock_bh(&bond->lock);
return ret;
} }
int bond_option_arp_validate_set(struct bonding *bond, int arp_validate) int bond_option_arp_ip_targets_set(struct bonding *bond,
struct bond_opt_value *newval)
{ {
if (bond_parm_tbl_lookup(arp_validate, arp_validate_tbl) < 0) { int ret = -EPERM;
pr_err("%s: Ignoring invalid arp_validate value %d.\n", __be32 target;
bond->dev->name, arp_validate);
return -EINVAL;
}
if (bond->params.mode != BOND_MODE_ACTIVEBACKUP) { if (newval->string) {
pr_err("%s: arp_validate only supported in active-backup mode.\n", if (!in4_pton(newval->string+1, -1, (u8 *)&target, -1, NULL)) {
pr_err("%s: invalid ARP target %pI4 specified\n",
bond->dev->name, &target);
return ret;
}
if (newval->string[0] == '+')
ret = bond_option_arp_ip_target_add(bond, target);
else if (newval->string[0] == '-')
ret = bond_option_arp_ip_target_rem(bond, target);
else
pr_err("no command found in arp_ip_targets file for bond %s. Use +<addr> or -<addr>.\n",
bond->dev->name); bond->dev->name);
return -EINVAL; } else {
target = newval->value;
ret = bond_option_arp_ip_target_add(bond, target);
} }
pr_info("%s: setting arp_validate to %s (%d).\n", return ret;
bond->dev->name, arp_validate_tbl[arp_validate].modename, }
arp_validate);
int bond_option_arp_validate_set(struct bonding *bond,
struct bond_opt_value *newval)
{
pr_info("%s: setting arp_validate to %s (%llu).\n",
bond->dev->name, newval->string, newval->value);
if (bond->dev->flags & IFF_UP) { if (bond->dev->flags & IFF_UP) {
if (!arp_validate) if (!newval->value)
bond->recv_probe = NULL; bond->recv_probe = NULL;
else if (bond->params.arp_interval) else if (bond->params.arp_interval)
bond->recv_probe = bond_arp_rcv; bond->recv_probe = bond_arp_rcv;
} }
bond->params.arp_validate = arp_validate; bond->params.arp_validate = newval->value;
return 0; return 0;
} }
int bond_option_arp_all_targets_set(struct bonding *bond, int arp_all_targets) int bond_option_arp_all_targets_set(struct bonding *bond,
struct bond_opt_value *newval)
{ {
if (bond_parm_tbl_lookup(arp_all_targets, arp_all_targets_tbl) < 0) { pr_info("%s: setting arp_all_targets to %s (%llu).\n",
pr_err("%s: Ignoring invalid arp_all_targets value %d.\n", bond->dev->name, newval->string, newval->value);
bond->dev->name, arp_all_targets); bond->params.arp_all_targets = newval->value;
return -EINVAL;
}
pr_info("%s: setting arp_all_targets to %s (%d).\n",
bond->dev->name, arp_all_targets_tbl[arp_all_targets].modename,
arp_all_targets);
bond->params.arp_all_targets = arp_all_targets;
return 0; return 0;
} }
int bond_option_primary_set(struct bonding *bond, const char *primary) int bond_option_primary_set(struct bonding *bond, struct bond_opt_value *newval)
{ {
char *p, *primary = newval->string;
struct list_head *iter; struct list_head *iter;
struct slave *slave; struct slave *slave;
int err = 0;
block_netpoll_tx(); block_netpoll_tx();
read_lock(&bond->lock); read_lock(&bond->lock);
write_lock_bh(&bond->curr_slave_lock); write_lock_bh(&bond->curr_slave_lock);
if (!USES_PRIMARY(bond->params.mode)) { p = strchr(primary, '\n');
pr_err("%s: Unable to set primary slave; %s is in mode %d\n", if (p)
bond->dev->name, bond->dev->name, bond->params.mode); *p = '\0';
err = -EINVAL;
goto out;
}
/* check to see if we are clearing primary */ /* check to see if we are clearing primary */
if (!strlen(primary)) { if (!strlen(primary)) {
pr_info("%s: Setting primary slave to None.\n", pr_info("%s: Setting primary slave to None.\n",
...@@ -522,21 +1032,15 @@ int bond_option_primary_set(struct bonding *bond, const char *primary) ...@@ -522,21 +1032,15 @@ int bond_option_primary_set(struct bonding *bond, const char *primary)
read_unlock(&bond->lock); read_unlock(&bond->lock);
unblock_netpoll_tx(); unblock_netpoll_tx();
return err; return 0;
} }
int bond_option_primary_reselect_set(struct bonding *bond, int primary_reselect) int bond_option_primary_reselect_set(struct bonding *bond,
struct bond_opt_value *newval)
{ {
if (bond_parm_tbl_lookup(primary_reselect, pri_reselect_tbl) < 0) { pr_info("%s: setting primary_reselect to %s (%llu).\n",
pr_err("%s: Ignoring invalid primary_reselect value %d.\n", bond->dev->name, newval->string, newval->value);
bond->dev->name, primary_reselect); bond->params.primary_reselect = newval->value;
return -EINVAL;
}
bond->params.primary_reselect = primary_reselect;
pr_info("%s: setting primary_reselect to %s (%d).\n",
bond->dev->name, pri_reselect_tbl[primary_reselect].modename,
primary_reselect);
block_netpoll_tx(); block_netpoll_tx();
write_lock_bh(&bond->curr_slave_lock); write_lock_bh(&bond->curr_slave_lock);
...@@ -547,85 +1051,56 @@ int bond_option_primary_reselect_set(struct bonding *bond, int primary_reselect) ...@@ -547,85 +1051,56 @@ int bond_option_primary_reselect_set(struct bonding *bond, int primary_reselect)
return 0; return 0;
} }
int bond_option_fail_over_mac_set(struct bonding *bond, int fail_over_mac) int bond_option_fail_over_mac_set(struct bonding *bond,
struct bond_opt_value *newval)
{ {
if (bond_parm_tbl_lookup(fail_over_mac, fail_over_mac_tbl) < 0) { pr_info("%s: Setting fail_over_mac to %s (%llu).\n",
pr_err("%s: Ignoring invalid fail_over_mac value %d.\n", bond->dev->name, newval->string, newval->value);
bond->dev->name, fail_over_mac); bond->params.fail_over_mac = newval->value;
return -EINVAL;
}
if (bond_has_slaves(bond)) {
pr_err("%s: Can't alter fail_over_mac with slaves in bond.\n",
bond->dev->name);
return -EPERM;
}
bond->params.fail_over_mac = fail_over_mac;
pr_info("%s: Setting fail_over_mac to %s (%d).\n",
bond->dev->name, fail_over_mac_tbl[fail_over_mac].modename,
fail_over_mac);
return 0; return 0;
} }
int bond_option_xmit_hash_policy_set(struct bonding *bond, int xmit_hash_policy) int bond_option_xmit_hash_policy_set(struct bonding *bond,
struct bond_opt_value *newval)
{ {
if (bond_parm_tbl_lookup(xmit_hash_policy, xmit_hashtype_tbl) < 0) { pr_info("%s: setting xmit hash policy to %s (%llu).\n",
pr_err("%s: Ignoring invalid xmit_hash_policy value %d.\n", bond->dev->name, newval->string, newval->value);
bond->dev->name, xmit_hash_policy); bond->params.xmit_policy = newval->value;
return -EINVAL;
}
bond->params.xmit_policy = xmit_hash_policy;
pr_info("%s: setting xmit hash policy to %s (%d).\n",
bond->dev->name,
xmit_hashtype_tbl[xmit_hash_policy].modename, xmit_hash_policy);
return 0; return 0;
} }
int bond_option_resend_igmp_set(struct bonding *bond, int resend_igmp) int bond_option_resend_igmp_set(struct bonding *bond,
struct bond_opt_value *newval)
{ {
if (resend_igmp < 0 || resend_igmp > 255) { pr_info("%s: Setting resend_igmp to %llu.\n",
pr_err("%s: Invalid resend_igmp value %d not in range 0-255; rejected.\n", bond->dev->name, newval->value);
bond->dev->name, resend_igmp); bond->params.resend_igmp = newval->value;
return -EINVAL;
}
bond->params.resend_igmp = resend_igmp;
pr_info("%s: Setting resend_igmp to %d.\n",
bond->dev->name, resend_igmp);
return 0; return 0;
} }
int bond_option_num_peer_notif_set(struct bonding *bond, int num_peer_notif) int bond_option_num_peer_notif_set(struct bonding *bond,
struct bond_opt_value *newval)
{ {
bond->params.num_peer_notif = num_peer_notif; bond->params.num_peer_notif = newval->value;
return 0; return 0;
} }
int bond_option_all_slaves_active_set(struct bonding *bond, int bond_option_all_slaves_active_set(struct bonding *bond,
int all_slaves_active) struct bond_opt_value *newval)
{ {
struct list_head *iter; struct list_head *iter;
struct slave *slave; struct slave *slave;
if (all_slaves_active == bond->params.all_slaves_active) if (newval->value == bond->params.all_slaves_active)
return 0; return 0;
bond->params.all_slaves_active = newval->value;
if ((all_slaves_active == 0) || (all_slaves_active == 1)) {
bond->params.all_slaves_active = all_slaves_active;
} else {
pr_info("%s: Ignoring invalid all_slaves_active value %d.\n",
bond->dev->name, all_slaves_active);
return -EINVAL;
}
bond_for_each_slave(bond, slave, iter) { bond_for_each_slave(bond, slave, iter) {
if (!bond_is_active_slave(slave)) { if (!bond_is_active_slave(slave)) {
if (all_slaves_active) if (newval->value)
slave->inactive = 0; slave->inactive = 0;
else else
slave->inactive = 1; slave->inactive = 1;
...@@ -635,45 +1110,30 @@ int bond_option_all_slaves_active_set(struct bonding *bond, ...@@ -635,45 +1110,30 @@ int bond_option_all_slaves_active_set(struct bonding *bond,
return 0; return 0;
} }
int bond_option_min_links_set(struct bonding *bond, int min_links) int bond_option_min_links_set(struct bonding *bond,
struct bond_opt_value *newval)
{ {
pr_info("%s: Setting min links value to %u\n", pr_info("%s: Setting min links value to %llu\n",
bond->dev->name, min_links); bond->dev->name, newval->value);
bond->params.min_links = min_links; bond->params.min_links = newval->value;
return 0; return 0;
} }
int bond_option_lp_interval_set(struct bonding *bond, int lp_interval) int bond_option_lp_interval_set(struct bonding *bond,
struct bond_opt_value *newval)
{ {
if (lp_interval <= 0) { bond->params.lp_interval = newval->value;
pr_err("%s: lp_interval must be between 1 and %d\n",
bond->dev->name, INT_MAX);
return -EINVAL;
}
bond->params.lp_interval = lp_interval;
return 0; return 0;
} }
int bond_option_packets_per_slave_set(struct bonding *bond, int bond_option_pps_set(struct bonding *bond, struct bond_opt_value *newval)
int packets_per_slave)
{ {
if (packets_per_slave < 0 || packets_per_slave > USHRT_MAX) { bond->params.packets_per_slave = newval->value;
pr_err("%s: packets_per_slave must be between 0 and %u\n", if (newval->value > 0) {
bond->dev->name, USHRT_MAX);
return -EINVAL;
}
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);
bond->params.packets_per_slave = packets_per_slave;
if (packets_per_slave > 0) {
bond->params.reciprocal_packets_per_slave = bond->params.reciprocal_packets_per_slave =
reciprocal_value(packets_per_slave); reciprocal_value(newval->value);
} else { } else {
/* reciprocal_packets_per_slave is unused if /* reciprocal_packets_per_slave is unused if
* packets_per_slave is 0 or 1, just initialize it * packets_per_slave is 0 or 1, just initialize it
...@@ -685,53 +1145,132 @@ int bond_option_packets_per_slave_set(struct bonding *bond, ...@@ -685,53 +1145,132 @@ int bond_option_packets_per_slave_set(struct bonding *bond,
return 0; return 0;
} }
int bond_option_lacp_rate_set(struct bonding *bond, int lacp_rate) int bond_option_lacp_rate_set(struct bonding *bond,
struct bond_opt_value *newval)
{ {
if (bond_parm_tbl_lookup(lacp_rate, bond_lacp_tbl) < 0) { pr_info("%s: Setting LACP rate to %s (%llu).\n",
pr_err("%s: Ignoring invalid LACP rate value %d.\n", bond->dev->name, newval->string, newval->value);
bond->dev->name, lacp_rate); bond->params.lacp_fast = newval->value;
return -EINVAL; bond_3ad_update_lacp_rate(bond);
}
if (bond->dev->flags & IFF_UP) {
pr_err("%s: Unable to update LACP rate because interface is up.\n",
bond->dev->name);
return -EPERM;
}
if (bond->params.mode != BOND_MODE_8023AD) { return 0;
pr_err("%s: Unable to update LACP rate because bond is not in 802.3ad mode.\n", }
bond->dev->name);
return -EPERM;
}
bond->params.lacp_fast = lacp_rate; int bond_option_ad_select_set(struct bonding *bond,
bond_3ad_update_lacp_rate(bond); struct bond_opt_value *newval)
pr_info("%s: Setting LACP rate to %s (%d).\n", {
bond->dev->name, bond_lacp_tbl[lacp_rate].modename, pr_info("%s: Setting ad_select to %s (%llu).\n",
lacp_rate); bond->dev->name, newval->string, newval->value);
bond->params.ad_select = newval->value;
return 0; return 0;
} }
int bond_option_ad_select_set(struct bonding *bond, int ad_select) int bond_option_queue_id_set(struct bonding *bond,
struct bond_opt_value *newval)
{ {
if (bond_parm_tbl_lookup(ad_select, ad_select_tbl) < 0) { struct slave *slave, *update_slave;
pr_err("%s: Ignoring invalid ad_select value %d.\n", struct net_device *sdev;
bond->dev->name, ad_select); struct list_head *iter;
return -EINVAL; char *delim;
int ret = 0;
u16 qid;
/* delim will point to queue id if successful */
delim = strchr(newval->string, ':');
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(newval->string) > IFNAMSIZ ||
!dev_valid_name(newval->string) ||
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), newval->string);
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 (bond->dev->flags & IFF_UP) { if (!update_slave)
pr_err("%s: Unable to update ad_select because interface is up.\n", goto err_no_cmd;
/* Actually set the qids for the slave */
update_slave->queue_id = qid;
out:
return ret;
err_no_cmd:
pr_info("invalid input for queue_id set for %s.\n",
bond->dev->name); bond->dev->name);
return -EPERM; ret = -EPERM;
goto out;
}
int bond_option_slaves_set(struct bonding *bond, struct bond_opt_value *newval)
{
char command[IFNAMSIZ + 1] = { 0, };
struct net_device *dev;
char *ifname;
int ret;
sscanf(newval->string, "%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;
} }
bond->params.ad_select = ad_select; switch (command[0]) {
pr_info("%s: Setting ad_select to %s (%d).\n", case '+':
bond->dev->name, ad_select_tbl[ad_select].modename, pr_info("%s: Adding slave %s.\n", bond->dev->name, dev->name);
ad_select); ret = bond_enslave(bond->dev, dev);
break;
return 0; case '-':
pr_info("%s: Removing slave %s.\n", bond->dev->name, dev->name);
ret = bond_release(bond->dev, dev);
break;
default:
goto err_no_cmd;
}
out:
return ret;
err_no_cmd:
pr_err("no command found in slaves file for bond %s. Use +ifname or -ifname.\n",
bond->dev->name);
ret = -EPERM;
goto out;
} }
/*
* drivers/net/bond/bond_options.h - bonding options
* Copyright (c) 2013 Nikolay Aleksandrov <nikolay@redhat.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#ifndef _BOND_OPTIONS_H
#define _BOND_OPTIONS_H
#define BOND_OPT_MAX_NAMELEN 32
#define BOND_OPT_VALID(opt) ((opt) < BOND_OPT_LAST)
#define BOND_MODE_ALL_EX(x) (~(x))
/* Option flags:
* BOND_OPTFLAG_NOSLAVES - check if the bond device is empty before setting
* BOND_OPTFLAG_IFDOWN - check if the bond device is down before setting
* BOND_OPTFLAG_RAWVAL - the option parses the value itself
*/
enum {
BOND_OPTFLAG_NOSLAVES = BIT(0),
BOND_OPTFLAG_IFDOWN = BIT(1),
BOND_OPTFLAG_RAWVAL = BIT(2)
};
/* Value type flags:
* BOND_VALFLAG_DEFAULT - mark the value as default
* BOND_VALFLAG_(MIN|MAX) - mark the value as min/max
*/
enum {
BOND_VALFLAG_DEFAULT = BIT(0),
BOND_VALFLAG_MIN = BIT(1),
BOND_VALFLAG_MAX = BIT(2)
};
/* Option IDs, their bit positions correspond to their IDs */
enum {
BOND_OPT_MODE,
BOND_OPT_PACKETS_PER_SLAVE,
BOND_OPT_XMIT_HASH,
BOND_OPT_ARP_VALIDATE,
BOND_OPT_ARP_ALL_TARGETS,
BOND_OPT_FAIL_OVER_MAC,
BOND_OPT_ARP_INTERVAL,
BOND_OPT_ARP_TARGETS,
BOND_OPT_DOWNDELAY,
BOND_OPT_UPDELAY,
BOND_OPT_LACP_RATE,
BOND_OPT_MINLINKS,
BOND_OPT_AD_SELECT,
BOND_OPT_NUM_PEER_NOTIF,
BOND_OPT_MIIMON,
BOND_OPT_PRIMARY,
BOND_OPT_PRIMARY_RESELECT,
BOND_OPT_USE_CARRIER,
BOND_OPT_ACTIVE_SLAVE,
BOND_OPT_QUEUE_ID,
BOND_OPT_ALL_SLAVES_ACTIVE,
BOND_OPT_RESEND_IGMP,
BOND_OPT_LP_INTERVAL,
BOND_OPT_SLAVES,
BOND_OPT_LAST
};
/* This structure is used for storing option values and for passing option
* values when changing an option. The logic when used as an arg is as follows:
* - if string != NULL -> parse it, if the opt is RAW type then return it, else
* return the parse result
* - if string == NULL -> parse value
*/
struct bond_opt_value {
char *string;
u64 value;
u32 flags;
};
struct bonding;
struct bond_option {
int id;
char *name;
char *desc;
u32 flags;
/* unsuppmodes is used to denote modes in which the option isn't
* supported.
*/
unsigned long unsuppmodes;
/* supported values which this option can have, can be a subset of
* BOND_OPTVAL_RANGE's value range
*/
struct bond_opt_value *values;
int (*set)(struct bonding *bond, struct bond_opt_value *val);
};
int __bond_opt_set(struct bonding *bond, unsigned int option,
struct bond_opt_value *val);
int bond_opt_tryset_rtnl(struct bonding *bond, unsigned int option, char *buf);
struct bond_opt_value *bond_opt_parse(const struct bond_option *opt,
struct bond_opt_value *val);
struct bond_option *bond_opt_get(unsigned int option);
struct bond_opt_value *bond_opt_get_val(unsigned int option, u64 val);
/* This helper is used to initialize a bond_opt_value structure for parameter
* passing. There should be either a valid string or value, but not both.
* When value is ULLONG_MAX then string will be used.
*/
static inline void __bond_opt_init(struct bond_opt_value *optval,
char *string, u64 value)
{
memset(optval, 0, sizeof(*optval));
optval->value = ULLONG_MAX;
if (value == ULLONG_MAX)
optval->string = string;
else
optval->value = value;
}
#define bond_opt_initval(optval, value) __bond_opt_init(optval, NULL, value)
#define bond_opt_initstr(optval, str) __bond_opt_init(optval, str, ULLONG_MAX)
int bond_option_mode_set(struct bonding *bond, struct bond_opt_value *newval);
int bond_option_pps_set(struct bonding *bond, struct bond_opt_value *newval);
int bond_option_xmit_hash_policy_set(struct bonding *bond,
struct bond_opt_value *newval);
int bond_option_arp_validate_set(struct bonding *bond,
struct bond_opt_value *newval);
int bond_option_arp_all_targets_set(struct bonding *bond,
struct bond_opt_value *newval);
int bond_option_fail_over_mac_set(struct bonding *bond,
struct bond_opt_value *newval);
int bond_option_arp_interval_set(struct bonding *bond,
struct bond_opt_value *newval);
int bond_option_arp_ip_targets_set(struct bonding *bond,
struct bond_opt_value *newval);
void bond_option_arp_ip_targets_clear(struct bonding *bond);
int bond_option_downdelay_set(struct bonding *bond,
struct bond_opt_value *newval);
int bond_option_updelay_set(struct bonding *bond,
struct bond_opt_value *newval);
int bond_option_lacp_rate_set(struct bonding *bond,
struct bond_opt_value *newval);
int bond_option_min_links_set(struct bonding *bond,
struct bond_opt_value *newval);
int bond_option_ad_select_set(struct bonding *bond,
struct bond_opt_value *newval);
int bond_option_num_peer_notif_set(struct bonding *bond,
struct bond_opt_value *newval);
int bond_option_miimon_set(struct bonding *bond, struct bond_opt_value *newval);
int bond_option_primary_set(struct bonding *bond,
struct bond_opt_value *newval);
int bond_option_primary_reselect_set(struct bonding *bond,
struct bond_opt_value *newval);
int bond_option_use_carrier_set(struct bonding *bond,
struct bond_opt_value *newval);
int bond_option_active_slave_set(struct bonding *bond,
struct bond_opt_value *newval);
int bond_option_queue_id_set(struct bonding *bond,
struct bond_opt_value *newval);
int bond_option_all_slaves_active_set(struct bonding *bond,
struct bond_opt_value *newval);
int bond_option_resend_igmp_set(struct bonding *bond,
struct bond_opt_value *newval);
int bond_option_lp_interval_set(struct bonding *bond,
struct bond_opt_value *newval);
int bond_option_slaves_set(struct bonding *bond, struct bond_opt_value *newval);
#endif /* _BOND_OPTIONS_H */
...@@ -65,6 +65,7 @@ static void bond_info_seq_stop(struct seq_file *seq, void *v) ...@@ -65,6 +65,7 @@ static void bond_info_seq_stop(struct seq_file *seq, void *v)
static void bond_info_show_master(struct seq_file *seq) static void bond_info_show_master(struct seq_file *seq)
{ {
struct bonding *bond = seq->private; struct bonding *bond = seq->private;
struct bond_opt_value *optval;
struct slave *curr; struct slave *curr;
int i; int i;
...@@ -76,26 +77,32 @@ static void bond_info_show_master(struct seq_file *seq) ...@@ -76,26 +77,32 @@ static void bond_info_show_master(struct seq_file *seq)
bond_mode_name(bond->params.mode)); bond_mode_name(bond->params.mode));
if (bond->params.mode == BOND_MODE_ACTIVEBACKUP && if (bond->params.mode == BOND_MODE_ACTIVEBACKUP &&
bond->params.fail_over_mac) bond->params.fail_over_mac) {
seq_printf(seq, " (fail_over_mac %s)", optval = bond_opt_get_val(BOND_OPT_FAIL_OVER_MAC,
fail_over_mac_tbl[bond->params.fail_over_mac].modename); bond->params.fail_over_mac);
seq_printf(seq, " (fail_over_mac %s)", optval->string);
}
seq_printf(seq, "\n"); seq_printf(seq, "\n");
if (bond->params.mode == BOND_MODE_XOR || if (bond->params.mode == BOND_MODE_XOR ||
bond->params.mode == BOND_MODE_8023AD) { bond->params.mode == BOND_MODE_8023AD) {
seq_printf(seq, "Transmit Hash Policy: %s (%d)\n", optval = bond_opt_get_val(BOND_OPT_XMIT_HASH,
xmit_hashtype_tbl[bond->params.xmit_policy].modename,
bond->params.xmit_policy); bond->params.xmit_policy);
seq_printf(seq, "Transmit Hash Policy: %s (%d)\n",
optval->string, bond->params.xmit_policy);
} }
if (USES_PRIMARY(bond->params.mode)) { if (USES_PRIMARY(bond->params.mode)) {
seq_printf(seq, "Primary Slave: %s", seq_printf(seq, "Primary Slave: %s",
(bond->primary_slave) ? (bond->primary_slave) ?
bond->primary_slave->dev->name : "None"); bond->primary_slave->dev->name : "None");
if (bond->primary_slave) if (bond->primary_slave) {
optval = bond_opt_get_val(BOND_OPT_PRIMARY_RESELECT,
bond->params.primary_reselect);
seq_printf(seq, " (primary_reselect %s)", seq_printf(seq, " (primary_reselect %s)",
pri_reselect_tbl[bond->params.primary_reselect].modename); optval->string);
}
seq_printf(seq, "\nCurrently Active Slave: %s\n", seq_printf(seq, "\nCurrently Active Slave: %s\n",
(curr) ? curr->dev->name : "None"); (curr) ? curr->dev->name : "None");
...@@ -136,8 +143,10 @@ static void bond_info_show_master(struct seq_file *seq) ...@@ -136,8 +143,10 @@ static void bond_info_show_master(struct seq_file *seq)
seq_printf(seq, "LACP rate: %s\n", seq_printf(seq, "LACP rate: %s\n",
(bond->params.lacp_fast) ? "fast" : "slow"); (bond->params.lacp_fast) ? "fast" : "slow");
seq_printf(seq, "Min links: %d\n", bond->params.min_links); seq_printf(seq, "Min links: %d\n", bond->params.min_links);
optval = bond_opt_get_val(BOND_OPT_AD_SELECT,
bond->params.ad_select);
seq_printf(seq, "Aggregator selection policy (ad_select): %s\n", seq_printf(seq, "Aggregator selection policy (ad_select): %s\n",
ad_select_tbl[bond->params.ad_select].modename); optval->string);
if (__bond_3ad_get_active_agg_info(bond, &ad_info)) { if (__bond_3ad_get_active_agg_info(bond, &ad_info)) {
seq_printf(seq, "bond %s has no active aggregator\n", seq_printf(seq, "bond %s has no active aggregator\n",
......
...@@ -200,58 +200,15 @@ static ssize_t bonding_store_slaves(struct device *d, ...@@ -200,58 +200,15 @@ static ssize_t bonding_store_slaves(struct device *d,
struct device_attribute *attr, struct device_attribute *attr,
const char *buffer, size_t count) 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); struct bonding *bond = to_bond(d);
int ret;
if (!rtnl_trylock()) ret = bond_opt_tryset_rtnl(bond, BOND_OPT_SLAVES, (char *)buffer);
return restart_syscall(); if (!ret)
ret = count;
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;
out:
rtnl_unlock();
return ret; return ret;
} }
static DEVICE_ATTR(slaves, S_IRUGO | S_IWUSR, bonding_show_slaves, static DEVICE_ATTR(slaves, S_IRUGO | S_IWUSR, bonding_show_slaves,
bonding_store_slaves); bonding_store_slaves);
...@@ -263,37 +220,24 @@ static ssize_t bonding_show_mode(struct device *d, ...@@ -263,37 +220,24 @@ static ssize_t bonding_show_mode(struct device *d,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
struct bonding *bond = to_bond(d); struct bonding *bond = to_bond(d);
struct bond_opt_value *val;
return sprintf(buf, "%s %d\n", val = bond_opt_get_val(BOND_OPT_MODE, bond->params.mode);
bond_mode_tbl[bond->params.mode].modename,
bond->params.mode); return sprintf(buf, "%s %d\n", val->string, bond->params.mode);
} }
static ssize_t bonding_store_mode(struct device *d, static ssize_t bonding_store_mode(struct device *d,
struct device_attribute *attr, struct device_attribute *attr,
const char *buf, size_t count) const char *buf, size_t count)
{ {
int new_value, ret;
struct bonding *bond = to_bond(d); struct bonding *bond = to_bond(d);
int ret;
new_value = bond_parse_parm(buf, bond_mode_tbl); ret = bond_opt_tryset_rtnl(bond, BOND_OPT_MODE, (char *)buf);
if (new_value < 0) { if (!ret)
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 = count; ret = count;
}
rtnl_unlock();
return ret; return ret;
} }
static DEVICE_ATTR(mode, S_IRUGO | S_IWUSR, static DEVICE_ATTR(mode, S_IRUGO | S_IWUSR,
...@@ -307,35 +251,24 @@ static ssize_t bonding_show_xmit_hash(struct device *d, ...@@ -307,35 +251,24 @@ static ssize_t bonding_show_xmit_hash(struct device *d,
char *buf) char *buf)
{ {
struct bonding *bond = to_bond(d); struct bonding *bond = to_bond(d);
struct bond_opt_value *val;
return sprintf(buf, "%s %d\n", val = bond_opt_get_val(BOND_OPT_XMIT_HASH, bond->params.xmit_policy);
xmit_hashtype_tbl[bond->params.xmit_policy].modename,
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, static ssize_t bonding_store_xmit_hash(struct device *d,
struct device_attribute *attr, struct device_attribute *attr,
const char *buf, size_t count) const char *buf, size_t count)
{ {
int new_value, ret;
struct bonding *bond = to_bond(d); struct bonding *bond = to_bond(d);
int ret;
new_value = bond_parse_parm(buf, xmit_hashtype_tbl); ret = bond_opt_tryset_rtnl(bond, BOND_OPT_XMIT_HASH, (char *)buf);
if (new_value < 0) {
pr_err("%s: Ignoring invalid xmit hash policy value %.*s.\n",
bond->dev->name,
(int)strlen(buf) - 1, buf);
return -EINVAL;
}
if (!rtnl_trylock())
return restart_syscall();
ret = bond_option_xmit_hash_policy_set(bond, new_value);
if (!ret) if (!ret)
ret = count; ret = count;
rtnl_unlock();
return ret; return ret;
} }
static DEVICE_ATTR(xmit_hash_policy, S_IRUGO | S_IWUSR, static DEVICE_ATTR(xmit_hash_policy, S_IRUGO | S_IWUSR,
...@@ -349,10 +282,12 @@ static ssize_t bonding_show_arp_validate(struct device *d, ...@@ -349,10 +282,12 @@ static ssize_t bonding_show_arp_validate(struct device *d,
char *buf) char *buf)
{ {
struct bonding *bond = to_bond(d); struct bonding *bond = to_bond(d);
struct bond_opt_value *val;
return sprintf(buf, "%s %d\n", val = bond_opt_get_val(BOND_OPT_ARP_VALIDATE,
arp_validate_tbl[bond->params.arp_validate].modename,
bond->params.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, static ssize_t bonding_store_arp_validate(struct device *d,
...@@ -360,23 +295,12 @@ static ssize_t bonding_store_arp_validate(struct device *d, ...@@ -360,23 +295,12 @@ static ssize_t bonding_store_arp_validate(struct device *d,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct bonding *bond = to_bond(d); struct bonding *bond = to_bond(d);
int new_value, ret; int ret;
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);
return -EINVAL;
}
if (!rtnl_trylock())
return restart_syscall();
ret = bond_option_arp_validate_set(bond, new_value); ret = bond_opt_tryset_rtnl(bond, BOND_OPT_ARP_VALIDATE, (char *)buf);
if (!ret) if (!ret)
ret = count; ret = count;
rtnl_unlock();
return ret; return ret;
} }
...@@ -390,10 +314,12 @@ static ssize_t bonding_show_arp_all_targets(struct device *d, ...@@ -390,10 +314,12 @@ static ssize_t bonding_show_arp_all_targets(struct device *d,
char *buf) char *buf)
{ {
struct bonding *bond = to_bond(d); 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, val = bond_opt_get_val(BOND_OPT_ARP_ALL_TARGETS,
value); 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, static ssize_t bonding_store_arp_all_targets(struct device *d,
...@@ -401,24 +327,12 @@ static ssize_t bonding_store_arp_all_targets(struct device *d, ...@@ -401,24 +327,12 @@ static ssize_t bonding_store_arp_all_targets(struct device *d,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct bonding *bond = to_bond(d); struct bonding *bond = to_bond(d);
int new_value, ret; int ret;
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;
}
if (!rtnl_trylock())
return restart_syscall();
ret = bond_option_arp_all_targets_set(bond, new_value); ret = bond_opt_tryset_rtnl(bond, BOND_OPT_ARP_ALL_TARGETS, (char *)buf);
if (!ret) if (!ret)
ret = count; ret = count;
rtnl_unlock();
return ret; return ret;
} }
...@@ -434,34 +348,25 @@ static ssize_t bonding_show_fail_over_mac(struct device *d, ...@@ -434,34 +348,25 @@ static ssize_t bonding_show_fail_over_mac(struct device *d,
char *buf) char *buf)
{ {
struct bonding *bond = to_bond(d); struct bonding *bond = to_bond(d);
struct bond_opt_value *val;
return sprintf(buf, "%s %d\n", val = bond_opt_get_val(BOND_OPT_FAIL_OVER_MAC,
fail_over_mac_tbl[bond->params.fail_over_mac].modename,
bond->params.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, static ssize_t bonding_store_fail_over_mac(struct device *d,
struct device_attribute *attr, struct device_attribute *attr,
const char *buf, size_t count) const char *buf, size_t count)
{ {
int new_value, ret;
struct bonding *bond = to_bond(d); struct bonding *bond = to_bond(d);
int ret;
new_value = bond_parse_parm(buf, fail_over_mac_tbl); ret = bond_opt_tryset_rtnl(bond, BOND_OPT_FAIL_OVER_MAC, (char *)buf);
if (new_value < 0) {
pr_err("%s: Ignoring invalid fail_over_mac value %s.\n",
bond->dev->name, buf);
return -EINVAL;
}
if (!rtnl_trylock())
return restart_syscall();
ret = bond_option_fail_over_mac_set(bond, new_value);
if (!ret) if (!ret)
ret = count; ret = count;
rtnl_unlock();
return ret; return ret;
} }
...@@ -488,22 +393,12 @@ static ssize_t bonding_store_arp_interval(struct device *d, ...@@ -488,22 +393,12 @@ static ssize_t bonding_store_arp_interval(struct device *d,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct bonding *bond = to_bond(d); struct bonding *bond = to_bond(d);
int new_value, ret; int ret;
if (sscanf(buf, "%d", &new_value) != 1) {
pr_err("%s: no arp_interval value specified.\n",
bond->dev->name);
return -EINVAL;
}
if (!rtnl_trylock())
return restart_syscall();
ret = bond_option_arp_interval_set(bond, new_value); ret = bond_opt_tryset_rtnl(bond, BOND_OPT_ARP_INTERVAL, (char *)buf);
if (!ret) if (!ret)
ret = count; ret = count;
rtnl_unlock();
return ret; return ret;
} }
static DEVICE_ATTR(arp_interval, S_IRUGO | S_IWUSR, static DEVICE_ATTR(arp_interval, S_IRUGO | S_IWUSR,
...@@ -516,8 +411,8 @@ static ssize_t bonding_show_arp_targets(struct device *d, ...@@ -516,8 +411,8 @@ static ssize_t bonding_show_arp_targets(struct device *d,
struct device_attribute *attr, struct device_attribute *attr,
char *buf) char *buf)
{ {
int i, res = 0;
struct bonding *bond = to_bond(d); struct bonding *bond = to_bond(d);
int i, res = 0;
for (i = 0; i < BOND_MAX_ARP_TARGETS; i++) { for (i = 0; i < BOND_MAX_ARP_TARGETS; i++) {
if (bond->params.arp_targets[i]) if (bond->params.arp_targets[i])
...@@ -526,6 +421,7 @@ static ssize_t bonding_show_arp_targets(struct device *d, ...@@ -526,6 +421,7 @@ static ssize_t bonding_show_arp_targets(struct device *d,
} }
if (res) if (res)
buf[res-1] = '\n'; /* eat the leftover space */ buf[res-1] = '\n'; /* eat the leftover space */
return res; return res;
} }
...@@ -534,30 +430,12 @@ static ssize_t bonding_store_arp_targets(struct device *d, ...@@ -534,30 +430,12 @@ static ssize_t bonding_store_arp_targets(struct device *d,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct bonding *bond = to_bond(d); struct bonding *bond = to_bond(d);
__be32 target; int ret;
int ret = -EPERM;
if (!in4_pton(buf + 1, -1, (u8 *)&target, -1, NULL)) {
pr_err("%s: invalid ARP target %pI4 specified\n",
bond->dev->name, &target);
return -EPERM;
}
if (!rtnl_trylock())
return restart_syscall();
if (buf[0] == '+')
ret = bond_option_arp_ip_target_add(bond, target);
else if (buf[0] == '-')
ret = bond_option_arp_ip_target_rem(bond, target);
else
pr_err("no command found in arp_ip_targets file for bond %s. Use +<addr> or -<addr>.\n",
bond->dev->name);
ret = bond_opt_tryset_rtnl(bond, BOND_OPT_ARP_TARGETS, (char *)buf);
if (!ret) if (!ret)
ret = count; ret = count;
rtnl_unlock();
return ret; return ret;
} }
static DEVICE_ATTR(arp_ip_target, S_IRUGO | S_IWUSR , bonding_show_arp_targets, bonding_store_arp_targets); static DEVICE_ATTR(arp_ip_target, S_IRUGO | S_IWUSR , bonding_show_arp_targets, bonding_store_arp_targets);
...@@ -580,22 +458,13 @@ static ssize_t bonding_store_downdelay(struct device *d, ...@@ -580,22 +458,13 @@ static ssize_t bonding_store_downdelay(struct device *d,
struct device_attribute *attr, struct device_attribute *attr,
const char *buf, size_t count) const char *buf, size_t count)
{ {
int new_value, ret;
struct bonding *bond = to_bond(d); struct bonding *bond = to_bond(d);
int ret;
if (sscanf(buf, "%d", &new_value) != 1) { ret = bond_opt_tryset_rtnl(bond, BOND_OPT_DOWNDELAY, (char *)buf);
pr_err("%s: no down delay value specified.\n", bond->dev->name);
return -EINVAL;
}
if (!rtnl_trylock())
return restart_syscall();
ret = bond_option_downdelay_set(bond, new_value);
if (!ret) if (!ret)
ret = count; ret = count;
rtnl_unlock();
return ret; return ret;
} }
static DEVICE_ATTR(downdelay, S_IRUGO | S_IWUSR, static DEVICE_ATTR(downdelay, S_IRUGO | S_IWUSR,
...@@ -615,23 +484,13 @@ static ssize_t bonding_store_updelay(struct device *d, ...@@ -615,23 +484,13 @@ static ssize_t bonding_store_updelay(struct device *d,
struct device_attribute *attr, struct device_attribute *attr,
const char *buf, size_t count) const char *buf, size_t count)
{ {
int new_value, ret;
struct bonding *bond = to_bond(d); struct bonding *bond = to_bond(d);
int ret;
if (sscanf(buf, "%d", &new_value) != 1) { ret = bond_opt_tryset_rtnl(bond, BOND_OPT_UPDELAY, (char *)buf);
pr_err("%s: no up delay value specified.\n",
bond->dev->name);
return -EINVAL;
}
if (!rtnl_trylock())
return restart_syscall();
ret = bond_option_updelay_set(bond, new_value);
if (!ret) if (!ret)
ret = count; ret = count;
rtnl_unlock();
return ret; return ret;
} }
static DEVICE_ATTR(updelay, S_IRUGO | S_IWUSR, static DEVICE_ATTR(updelay, S_IRUGO | S_IWUSR,
...@@ -646,10 +505,11 @@ static ssize_t bonding_show_lacp(struct device *d, ...@@ -646,10 +505,11 @@ static ssize_t bonding_show_lacp(struct device *d,
char *buf) char *buf)
{ {
struct bonding *bond = to_bond(d); struct bonding *bond = to_bond(d);
struct bond_opt_value *val;
return sprintf(buf, "%s %d\n", val = bond_opt_get_val(BOND_OPT_LACP_RATE, bond->params.lacp_fast);
bond_lacp_tbl[bond->params.lacp_fast].modename,
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, static ssize_t bonding_store_lacp(struct device *d,
...@@ -657,23 +517,12 @@ static ssize_t bonding_store_lacp(struct device *d, ...@@ -657,23 +517,12 @@ static ssize_t bonding_store_lacp(struct device *d,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct bonding *bond = to_bond(d); struct bonding *bond = to_bond(d);
int new_value, ret; int ret;
new_value = bond_parse_parm(buf, bond_lacp_tbl);
if (new_value < 0) {
pr_err("%s: Ignoring invalid LACP rate value %.*s.\n",
bond->dev->name, (int)strlen(buf) - 1, buf);
return -EINVAL;
}
if (!rtnl_trylock())
return restart_syscall();
ret = bond_option_lacp_rate_set(bond, new_value); ret = bond_opt_tryset_rtnl(bond, BOND_OPT_LACP_RATE, (char *)buf);
if (!ret) if (!ret)
ret = count; ret = count;
rtnl_unlock();
return ret; return ret;
} }
static DEVICE_ATTR(lacp_rate, S_IRUGO | S_IWUSR, static DEVICE_ATTR(lacp_rate, S_IRUGO | S_IWUSR,
...@@ -694,23 +543,11 @@ static ssize_t bonding_store_min_links(struct device *d, ...@@ -694,23 +543,11 @@ static ssize_t bonding_store_min_links(struct device *d,
{ {
struct bonding *bond = to_bond(d); struct bonding *bond = to_bond(d);
int ret; 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;
}
if (!rtnl_trylock()) ret = bond_opt_tryset_rtnl(bond, BOND_OPT_MINLINKS, (char *)buf);
return restart_syscall();
ret = bond_option_min_links_set(bond, new_value);
if (!ret) if (!ret)
ret = count; ret = count;
rtnl_unlock();
return ret; return ret;
} }
static DEVICE_ATTR(min_links, S_IRUGO | S_IWUSR, static DEVICE_ATTR(min_links, S_IRUGO | S_IWUSR,
...@@ -721,10 +558,11 @@ static ssize_t bonding_show_ad_select(struct device *d, ...@@ -721,10 +558,11 @@ static ssize_t bonding_show_ad_select(struct device *d,
char *buf) char *buf)
{ {
struct bonding *bond = to_bond(d); struct bonding *bond = to_bond(d);
struct bond_opt_value *val;
return sprintf(buf, "%s %d\n", val = bond_opt_get_val(BOND_OPT_AD_SELECT, bond->params.ad_select);
ad_select_tbl[bond->params.ad_select].modename,
bond->params.ad_select); return sprintf(buf, "%s %d\n", val->string, bond->params.ad_select);
} }
...@@ -732,24 +570,13 @@ static ssize_t bonding_store_ad_select(struct device *d, ...@@ -732,24 +570,13 @@ static ssize_t bonding_store_ad_select(struct device *d,
struct device_attribute *attr, struct device_attribute *attr,
const char *buf, size_t count) const char *buf, size_t count)
{ {
int new_value, ret;
struct bonding *bond = to_bond(d); struct bonding *bond = to_bond(d);
int ret;
new_value = bond_parse_parm(buf, ad_select_tbl); ret = bond_opt_tryset_rtnl(bond, BOND_OPT_AD_SELECT, (char *)buf);
if (new_value < 0) {
pr_err("%s: Ignoring invalid ad_select value %.*s.\n",
bond->dev->name, (int)strlen(buf) - 1, buf);
return -EINVAL;
}
if (!rtnl_trylock())
return restart_syscall();
ret = bond_option_ad_select_set(bond, new_value);
if (!ret) if (!ret)
ret = count; ret = count;
rtnl_unlock();
return ret; return ret;
} }
static DEVICE_ATTR(ad_select, S_IRUGO | S_IWUSR, static DEVICE_ATTR(ad_select, S_IRUGO | S_IWUSR,
...@@ -771,24 +598,12 @@ static ssize_t bonding_store_num_peer_notif(struct device *d, ...@@ -771,24 +598,12 @@ static ssize_t bonding_store_num_peer_notif(struct device *d,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct bonding *bond = to_bond(d); struct bonding *bond = to_bond(d);
u8 new_value;
int ret; int ret;
ret = kstrtou8(buf, 10, &new_value); ret = bond_opt_tryset_rtnl(bond, BOND_OPT_NUM_PEER_NOTIF, (char *)buf);
if (ret) {
pr_err("%s: invalid value %s specified.\n",
bond->dev->name, buf);
return ret;
}
if (!rtnl_trylock())
return restart_syscall();
ret = bond_option_num_peer_notif_set(bond, new_value);
if (!ret) if (!ret)
ret = count; ret = count;
rtnl_unlock();
return ret; return ret;
} }
static DEVICE_ATTR(num_grat_arp, S_IRUGO | S_IWUSR, static DEVICE_ATTR(num_grat_arp, S_IRUGO | S_IWUSR,
...@@ -815,23 +630,13 @@ static ssize_t bonding_store_miimon(struct device *d, ...@@ -815,23 +630,13 @@ static ssize_t bonding_store_miimon(struct device *d,
struct device_attribute *attr, struct device_attribute *attr,
const char *buf, size_t count) const char *buf, size_t count)
{ {
int new_value, ret;
struct bonding *bond = to_bond(d); struct bonding *bond = to_bond(d);
int ret;
if (sscanf(buf, "%d", &new_value) != 1) { ret = bond_opt_tryset_rtnl(bond, BOND_OPT_MIIMON, (char *)buf);
pr_err("%s: no miimon value specified.\n",
bond->dev->name);
return -EINVAL;
}
if (!rtnl_trylock())
return restart_syscall();
ret = bond_option_miimon_set(bond, new_value);
if (!ret) if (!ret)
ret = count; ret = count;
rtnl_unlock();
return ret; return ret;
} }
static DEVICE_ATTR(miimon, S_IRUGO | S_IWUSR, static DEVICE_ATTR(miimon, S_IRUGO | S_IWUSR,
...@@ -862,21 +667,12 @@ static ssize_t bonding_store_primary(struct device *d, ...@@ -862,21 +667,12 @@ static ssize_t bonding_store_primary(struct device *d,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct bonding *bond = to_bond(d); struct bonding *bond = to_bond(d);
char ifname[IFNAMSIZ];
int ret; int ret;
sscanf(buf, "%15s", ifname); /* IFNAMSIZ */ ret = bond_opt_tryset_rtnl(bond, BOND_OPT_PRIMARY, (char *)buf);
if (ifname[0] == '\n')
ifname[0] = '\0';
if (!rtnl_trylock())
return restart_syscall();
ret = bond_option_primary_set(bond, ifname);
if (!ret) if (!ret)
ret = count; ret = count;
rtnl_unlock();
return ret; return ret;
} }
static DEVICE_ATTR(primary, S_IRUGO | S_IWUSR, static DEVICE_ATTR(primary, S_IRUGO | S_IWUSR,
...@@ -890,35 +686,27 @@ static ssize_t bonding_show_primary_reselect(struct device *d, ...@@ -890,35 +686,27 @@ static ssize_t bonding_show_primary_reselect(struct device *d,
char *buf) char *buf)
{ {
struct bonding *bond = to_bond(d); struct bonding *bond = to_bond(d);
struct bond_opt_value *val;
return sprintf(buf, "%s %d\n", val = bond_opt_get_val(BOND_OPT_PRIMARY_RESELECT,
pri_reselect_tbl[bond->params.primary_reselect].modename,
bond->params.primary_reselect); bond->params.primary_reselect);
return sprintf(buf, "%s %d\n",
val->string, bond->params.primary_reselect);
} }
static ssize_t bonding_store_primary_reselect(struct device *d, static ssize_t bonding_store_primary_reselect(struct device *d,
struct device_attribute *attr, struct device_attribute *attr,
const char *buf, size_t count) const char *buf, size_t count)
{ {
int new_value, ret;
struct bonding *bond = to_bond(d); struct bonding *bond = to_bond(d);
int ret;
new_value = bond_parse_parm(buf, pri_reselect_tbl); ret = bond_opt_tryset_rtnl(bond, BOND_OPT_PRIMARY_RESELECT,
if (new_value < 0) { (char *)buf);
pr_err("%s: Ignoring invalid primary_reselect value %.*s.\n",
bond->dev->name,
(int) strlen(buf) - 1, buf);
return -EINVAL;
}
if (!rtnl_trylock())
return restart_syscall();
ret = bond_option_primary_reselect_set(bond, new_value);
if (!ret) if (!ret)
ret = count; ret = count;
rtnl_unlock();
return ret; return ret;
} }
static DEVICE_ATTR(primary_reselect, S_IRUGO | S_IWUSR, static DEVICE_ATTR(primary_reselect, S_IRUGO | S_IWUSR,
...@@ -941,23 +729,13 @@ static ssize_t bonding_store_carrier(struct device *d, ...@@ -941,23 +729,13 @@ static ssize_t bonding_store_carrier(struct device *d,
struct device_attribute *attr, struct device_attribute *attr,
const char *buf, size_t count) const char *buf, size_t count)
{ {
int new_value, ret;
struct bonding *bond = to_bond(d); struct bonding *bond = to_bond(d);
int ret;
if (sscanf(buf, "%d", &new_value) != 1) { ret = bond_opt_tryset_rtnl(bond, BOND_OPT_USE_CARRIER, (char *)buf);
pr_err("%s: no use_carrier value specified.\n",
bond->dev->name);
return -EINVAL;
}
if (!rtnl_trylock())
return restart_syscall();
ret = bond_option_use_carrier_set(bond, new_value);
if (!ret) if (!ret)
ret = count; ret = count;
rtnl_unlock();
return ret; return ret;
} }
static DEVICE_ATTR(use_carrier, S_IRUGO | S_IWUSR, static DEVICE_ATTR(use_carrier, S_IRUGO | S_IWUSR,
...@@ -988,34 +766,14 @@ static ssize_t bonding_store_active_slave(struct device *d, ...@@ -988,34 +766,14 @@ static ssize_t bonding_store_active_slave(struct device *d,
struct device_attribute *attr, struct device_attribute *attr,
const char *buf, size_t count) const char *buf, size_t count)
{ {
int ret;
struct bonding *bond = to_bond(d); struct bonding *bond = to_bond(d);
char ifname[IFNAMSIZ]; int ret;
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;
}
}
ret = bond_option_active_slave_set(bond, dev); ret = bond_opt_tryset_rtnl(bond, BOND_OPT_ACTIVE_SLAVE, (char *)buf);
if (!ret) if (!ret)
ret = count; ret = count;
out:
rtnl_unlock();
return ret; return ret;
} }
static DEVICE_ATTR(active_slave, S_IRUGO | S_IWUSR, static DEVICE_ATTR(active_slave, S_IRUGO | S_IWUSR,
bonding_show_active_slave, bonding_store_active_slave); bonding_show_active_slave, bonding_store_active_slave);
...@@ -1184,72 +942,15 @@ static ssize_t bonding_store_queue_id(struct device *d, ...@@ -1184,72 +942,15 @@ static ssize_t bonding_store_queue_id(struct device *d,
struct device_attribute *attr, struct device_attribute *attr,
const char *buffer, size_t count) const char *buffer, size_t count)
{ {
struct slave *slave, *update_slave;
struct bonding *bond = to_bond(d); struct bonding *bond = to_bond(d);
struct list_head *iter; int ret;
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;
/* Actually set the qids for the slave */ ret = bond_opt_tryset_rtnl(bond, BOND_OPT_QUEUE_ID, (char *)buffer);
update_slave->queue_id = qid; if (!ret)
ret = count;
out:
rtnl_unlock();
return ret; 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, static DEVICE_ATTR(queue_id, S_IRUGO | S_IWUSR, bonding_show_queue_id,
bonding_store_queue_id); bonding_store_queue_id);
...@@ -1271,22 +972,13 @@ static ssize_t bonding_store_slaves_active(struct device *d, ...@@ -1271,22 +972,13 @@ static ssize_t bonding_store_slaves_active(struct device *d,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct bonding *bond = to_bond(d); struct bonding *bond = to_bond(d);
int new_value, ret; int ret;
if (sscanf(buf, "%d", &new_value) != 1) {
pr_err("%s: no all_slaves_active value specified.\n",
bond->dev->name);
return -EINVAL;
}
if (!rtnl_trylock())
return restart_syscall();
ret = bond_option_all_slaves_active_set(bond, new_value); ret = bond_opt_tryset_rtnl(bond, BOND_OPT_ALL_SLAVES_ACTIVE,
(char *)buf);
if (!ret) if (!ret)
ret = count; ret = count;
rtnl_unlock();
return ret; return ret;
} }
static DEVICE_ATTR(all_slaves_active, S_IRUGO | S_IWUSR, static DEVICE_ATTR(all_slaves_active, S_IRUGO | S_IWUSR,
...@@ -1308,23 +1000,13 @@ static ssize_t bonding_store_resend_igmp(struct device *d, ...@@ -1308,23 +1000,13 @@ static ssize_t bonding_store_resend_igmp(struct device *d,
struct device_attribute *attr, struct device_attribute *attr,
const char *buf, size_t count) const char *buf, size_t count)
{ {
int new_value, ret = count;
struct bonding *bond = to_bond(d); struct bonding *bond = to_bond(d);
int ret;
if (sscanf(buf, "%d", &new_value) != 1) { ret = bond_opt_tryset_rtnl(bond, BOND_OPT_RESEND_IGMP, (char *)buf);
pr_err("%s: no resend_igmp value specified.\n",
bond->dev->name);
return -EINVAL;
}
if (!rtnl_trylock())
return restart_syscall();
ret = bond_option_resend_igmp_set(bond, new_value);
if (!ret) if (!ret)
ret = count; ret = count;
rtnl_unlock();
return ret; return ret;
} }
...@@ -1345,22 +1027,12 @@ static ssize_t bonding_store_lp_interval(struct device *d, ...@@ -1345,22 +1027,12 @@ static ssize_t bonding_store_lp_interval(struct device *d,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct bonding *bond = to_bond(d); struct bonding *bond = to_bond(d);
int new_value, ret; int ret;
if (sscanf(buf, "%d", &new_value) != 1) {
pr_err("%s: no lp interval value specified.\n",
bond->dev->name);
return -EINVAL;
}
if (!rtnl_trylock())
return restart_syscall();
ret = bond_option_lp_interval_set(bond, new_value); ret = bond_opt_tryset_rtnl(bond, BOND_OPT_LP_INTERVAL, (char *)buf);
if (!ret) if (!ret)
ret = count; ret = count;
rtnl_unlock();
return ret; return ret;
} }
...@@ -1381,22 +1053,13 @@ static ssize_t bonding_store_packets_per_slave(struct device *d, ...@@ -1381,22 +1053,13 @@ static ssize_t bonding_store_packets_per_slave(struct device *d,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct bonding *bond = to_bond(d); struct bonding *bond = to_bond(d);
int new_value, ret; int ret;
if (sscanf(buf, "%d", &new_value) != 1) {
pr_err("%s: no packets_per_slave value specified.\n",
bond->dev->name);
return -EINVAL;
}
if (!rtnl_trylock())
return restart_syscall();
ret = bond_option_packets_per_slave_set(bond, new_value); ret = bond_opt_tryset_rtnl(bond, BOND_OPT_PACKETS_PER_SLAVE,
(char *)buf);
if (!ret) if (!ret)
ret = count; ret = count;
rtnl_unlock();
return ret; return ret;
} }
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include "bond_3ad.h" #include "bond_3ad.h"
#include "bond_alb.h" #include "bond_alb.h"
#include "bond_options.h"
#define DRV_VERSION "3.7.1" #define DRV_VERSION "3.7.1"
#define DRV_RELDATE "April 27, 2011" #define DRV_RELDATE "April 27, 2011"
...@@ -451,35 +452,8 @@ void bond_setup(struct net_device *bond_dev); ...@@ -451,35 +452,8 @@ void bond_setup(struct net_device *bond_dev);
unsigned int bond_get_num_tx_queues(void); unsigned int bond_get_num_tx_queues(void);
int bond_netlink_init(void); int bond_netlink_init(void);
void bond_netlink_fini(void); void bond_netlink_fini(void);
int bond_option_mode_set(struct bonding *bond, int mode);
int bond_option_active_slave_set(struct bonding *bond, struct net_device *slave_dev);
int bond_option_miimon_set(struct bonding *bond, int miimon);
int bond_option_updelay_set(struct bonding *bond, int updelay);
int bond_option_downdelay_set(struct bonding *bond, int downdelay);
int bond_option_use_carrier_set(struct bonding *bond, int use_carrier);
int bond_option_arp_interval_set(struct bonding *bond, int arp_interval);
int bond_option_arp_ip_targets_set(struct bonding *bond, __be32 *targets,
int count);
int bond_option_arp_ip_target_add(struct bonding *bond, __be32 target); int bond_option_arp_ip_target_add(struct bonding *bond, __be32 target);
int bond_option_arp_ip_target_rem(struct bonding *bond, __be32 target); int bond_option_arp_ip_target_rem(struct bonding *bond, __be32 target);
int bond_option_arp_validate_set(struct bonding *bond, int arp_validate);
int bond_option_arp_all_targets_set(struct bonding *bond, int arp_all_targets);
int bond_option_primary_set(struct bonding *bond, const char *primary);
int bond_option_primary_reselect_set(struct bonding *bond,
int primary_reselect);
int bond_option_fail_over_mac_set(struct bonding *bond, int fail_over_mac);
int bond_option_xmit_hash_policy_set(struct bonding *bond,
int xmit_hash_policy);
int bond_option_resend_igmp_set(struct bonding *bond, int resend_igmp);
int bond_option_num_peer_notif_set(struct bonding *bond, int num_peer_notif);
int bond_option_all_slaves_active_set(struct bonding *bond,
int all_slaves_active);
int bond_option_min_links_set(struct bonding *bond, int min_links);
int bond_option_lp_interval_set(struct bonding *bond, int min_links);
int bond_option_packets_per_slave_set(struct bonding *bond,
int packets_per_slave);
int bond_option_lacp_rate_set(struct bonding *bond, int lacp_rate);
int bond_option_ad_select_set(struct bonding *bond, int ad_select);
struct net_device *bond_option_active_slave_get_rcu(struct bonding *bond); struct net_device *bond_option_active_slave_get_rcu(struct bonding *bond);
struct net_device *bond_option_active_slave_get(struct bonding *bond); struct net_device *bond_option_active_slave_get(struct bonding *bond);
const char *bond_slave_link_status(s8 link); const char *bond_slave_link_status(s8 link);
...@@ -562,7 +536,6 @@ static inline int bond_get_targets_ip(__be32 *targets, __be32 ip) ...@@ -562,7 +536,6 @@ static inline int bond_get_targets_ip(__be32 *targets, __be32 ip)
/* exported from bond_main.c */ /* exported from bond_main.c */
extern int bond_net_id; extern int bond_net_id;
extern const struct bond_parm_tbl bond_lacp_tbl[]; extern const struct bond_parm_tbl bond_lacp_tbl[];
extern const struct bond_parm_tbl bond_mode_tbl[];
extern const struct bond_parm_tbl xmit_hashtype_tbl[]; extern const struct bond_parm_tbl xmit_hashtype_tbl[];
extern const struct bond_parm_tbl arp_validate_tbl[]; extern const struct bond_parm_tbl arp_validate_tbl[];
extern const struct bond_parm_tbl arp_all_targets_tbl[]; extern const struct bond_parm_tbl arp_all_targets_tbl[];
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment