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: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2014-01-22 15:39:18 -08:00
commit b414ac9a3e
7 changed files with 1222 additions and 888 deletions

View File

@ -86,13 +86,11 @@
/*---------------------------- Module parameters ----------------------------*/
/* 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 tx_queues = BOND_DEFAULT_TX_QUEUES;
static int num_peer_notif = 1;
static int miimon = BOND_LINK_MON_INTERV;
static int miimon;
static int updelay;
static int downdelay;
static int use_carrier = 1;
@ -103,7 +101,7 @@ static char *lacp_rate;
static int min_links;
static char *ad_select;
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_validate;
static char *arp_all_targets;
@ -208,67 +206,6 @@ static int bond_mode = BOND_MODE_ROUNDROBIN;
static int xmit_hashtype = BOND_XMIT_POLICY_LAYER2;
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 ---------------------------*/
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
struct ifslave k_sinfo;
struct ifslave __user *u_sinfo = NULL;
struct mii_ioctl_data *mii = NULL;
struct bond_opt_value newval;
struct net *net;
int res = 0;
@ -3281,7 +3219,8 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd
break;
case BOND_CHANGE_ACTIVE_OLD:
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;
default:
res = -EOPNOTSUPP;
@ -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)
{
int arp_validate_value, fail_over_mac_value, primary_reselect_value, i;
struct bond_opt_value newval, *valptr;
int arp_all_targets_value;
/*
* Convert string parameters.
*/
if (mode) {
bond_mode = bond_parse_parm(mode, bond_mode_tbl);
if (bond_mode == -1) {
pr_err("Error: Invalid bonding mode \"%s\"\n",
mode == NULL ? "NULL" : mode);
bond_opt_initstr(&newval, mode);
valptr = bond_opt_parse(bond_opt_get(BOND_OPT_MODE), &newval);
if (!valptr) {
pr_err("Error: Invalid bonding mode \"%s\"\n", mode);
return -EINVAL;
}
bond_mode = valptr->value;
}
if (xmit_hash_policy) {
@ -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",
bond_mode_name(bond_mode));
} else {
xmit_hashtype = bond_parse_parm(xmit_hash_policy,
xmit_hashtype_tbl);
if (xmit_hashtype == -1) {
bond_opt_initstr(&newval, xmit_hash_policy);
valptr = bond_opt_parse(bond_opt_get(BOND_OPT_XMIT_HASH),
&newval);
if (!valptr) {
pr_err("Error: Invalid xmit_hash_policy \"%s\"\n",
xmit_hash_policy == NULL ? "NULL" :
xmit_hash_policy);
return -EINVAL;
}
xmit_hashtype = valptr->value;
}
}
@ -4064,26 +4006,29 @@ static int bond_check_params(struct bond_params *params)
pr_info("lacp_rate param is irrelevant in mode %s\n",
bond_mode_name(bond_mode));
} else {
lacp_fast = bond_parse_parm(lacp_rate, bond_lacp_tbl);
if (lacp_fast == -1) {
bond_opt_initstr(&newval, lacp_rate);
valptr = bond_opt_parse(bond_opt_get(BOND_OPT_LACP_RATE),
&newval);
if (!valptr) {
pr_err("Error: Invalid lacp rate \"%s\"\n",
lacp_rate == NULL ? "NULL" : lacp_rate);
lacp_rate);
return -EINVAL;
}
lacp_fast = valptr->value;
}
}
if (ad_select) {
params->ad_select = bond_parse_parm(ad_select, ad_select_tbl);
if (params->ad_select == -1) {
pr_err("Error: Invalid ad_select \"%s\"\n",
ad_select == NULL ? "NULL" : ad_select);
bond_opt_initstr(&newval, lacp_rate);
valptr = bond_opt_parse(bond_opt_get(BOND_OPT_AD_SELECT),
&newval);
if (!valptr) {
pr_err("Error: Invalid ad_select \"%s\"\n", ad_select);
return -EINVAL;
}
if (bond_mode != BOND_MODE_8023AD) {
params->ad_select = valptr->value;
if (bond_mode != BOND_MODE_8023AD)
pr_warning("ad_select param only affects 802.3ad mode\n");
}
} else {
params->ad_select = BOND_AD_STABLE;
}
@ -4095,9 +4040,9 @@ static int bond_check_params(struct bond_params *params)
}
if (miimon < 0) {
pr_warning("Warning: miimon module parameter (%d), not in range 0-%d, so it was reset to %d\n",
miimon, INT_MAX, BOND_LINK_MON_INTERV);
miimon = BOND_LINK_MON_INTERV;
pr_warning("Warning: miimon module parameter (%d), not in range 0-%d, so it was reset to 0\n",
miimon, INT_MAX);
miimon = 0;
}
if (updelay < 0) {
@ -4154,7 +4099,8 @@ static int bond_check_params(struct bond_params *params)
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",
packets_per_slave, USHRT_MAX);
packets_per_slave = 1;
@ -4199,9 +4145,9 @@ static int bond_check_params(struct bond_params *params)
}
if (arp_interval < 0) {
pr_warning("Warning: arp_interval module parameter (%d) , not in range 0-%d, so it was reset to %d\n",
arp_interval, INT_MAX, BOND_LINK_ARP_INTERV);
arp_interval = BOND_LINK_ARP_INTERV;
pr_warning("Warning: arp_interval module parameter (%d) , not in range 0-%d, so it was reset to 0\n",
arp_interval, INT_MAX);
arp_interval = 0;
}
for (arp_ip_count = 0, i = 0;
@ -4240,35 +4186,40 @@ static int bond_check_params(struct bond_params *params)
return -EINVAL;
}
arp_validate_value = bond_parse_parm(arp_validate,
arp_validate_tbl);
if (arp_validate_value == -1) {
bond_opt_initstr(&newval, arp_validate);
valptr = bond_opt_parse(bond_opt_get(BOND_OPT_ARP_VALIDATE),
&newval);
if (!valptr) {
pr_err("Error: invalid arp_validate \"%s\"\n",
arp_validate == NULL ? "NULL" : arp_validate);
arp_validate);
return -EINVAL;
}
} else
arp_validate_value = valptr->value;
} else {
arp_validate_value = 0;
}
arp_all_targets_value = 0;
if (arp_all_targets) {
arp_all_targets_value = bond_parse_parm(arp_all_targets,
arp_all_targets_tbl);
if (arp_all_targets_value == -1) {
bond_opt_initstr(&newval, arp_all_targets);
valptr = bond_opt_parse(bond_opt_get(BOND_OPT_ARP_ALL_TARGETS),
&newval);
if (!valptr) {
pr_err("Error: invalid arp_all_targets_value \"%s\"\n",
arp_all_targets);
arp_all_targets_value = 0;
} else {
arp_all_targets_value = valptr->value;
}
}
if (miimon) {
pr_info("MII link monitoring set to %d ms\n", miimon);
} 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):",
arp_interval,
arp_validate_tbl[arp_validate_value].modename,
arp_ip_count);
arp_interval, valptr->string, arp_ip_count);
for (i = 0; i < arp_ip_count; i++)
pr_info(" %s", arp_ip_target[i]);
@ -4292,27 +4243,29 @@ static int bond_check_params(struct bond_params *params)
}
if (primary && primary_reselect) {
primary_reselect_value = bond_parse_parm(primary_reselect,
pri_reselect_tbl);
if (primary_reselect_value == -1) {
bond_opt_initstr(&newval, primary_reselect);
valptr = bond_opt_parse(bond_opt_get(BOND_OPT_PRIMARY_RESELECT),
&newval);
if (!valptr) {
pr_err("Error: Invalid primary_reselect \"%s\"\n",
primary_reselect ==
NULL ? "NULL" : primary_reselect);
primary_reselect);
return -EINVAL;
}
primary_reselect_value = valptr->value;
} else {
primary_reselect_value = BOND_PRI_RESELECT_ALWAYS;
}
if (fail_over_mac) {
fail_over_mac_value = bond_parse_parm(fail_over_mac,
fail_over_mac_tbl);
if (fail_over_mac_value == -1) {
bond_opt_initstr(&newval, fail_over_mac);
valptr = bond_opt_parse(bond_opt_get(BOND_OPT_FAIL_OVER_MAC),
&newval);
if (!valptr) {
pr_err("Error: invalid fail_over_mac \"%s\"\n",
arp_validate == NULL ? "NULL" : arp_validate);
fail_over_mac);
return -EINVAL;
}
fail_over_mac_value = valptr->value;
if (bond_mode != BOND_MODE_ACTIVEBACKUP)
pr_warning("Warning: fail_over_mac only affects active-backup mode.\n");
} else {

View File

@ -98,6 +98,7 @@ static int bond_changelink(struct net_device *bond_dev,
struct nlattr *tb[], struct nlattr *data[])
{
struct bonding *bond = netdev_priv(bond_dev);
struct bond_opt_value newval;
int miimon = 0;
int err;
@ -107,51 +108,57 @@ static int bond_changelink(struct net_device *bond_dev,
if (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)
return err;
}
if (data[IFLA_BOND_ACTIVE_SLAVE]) {
int ifindex = nla_get_u32(data[IFLA_BOND_ACTIVE_SLAVE]);
struct net_device *slave_dev;
char *active_slave = "";
if (ifindex == 0) {
slave_dev = NULL;
} else {
if (ifindex != 0) {
slave_dev = __dev_get_by_index(dev_net(bond_dev),
ifindex);
if (!slave_dev)
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)
return err;
}
if (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)
return err;
}
if (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)
return err;
}
if (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)
return err;
}
if (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)
return err;
}
@ -164,21 +171,29 @@ static int bond_changelink(struct net_device *bond_dev,
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)
return err;
}
if (data[IFLA_BOND_ARP_IP_TARGET]) {
__be32 targets[BOND_MAX_ARP_TARGETS] = { 0, };
struct nlattr *attr;
int i = 0, rem;
bond_option_arp_ip_targets_clear(bond);
nla_for_each_nested(attr, data[IFLA_BOND_ARP_IP_TARGET], rem) {
__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)
return err;
}
@ -191,7 +206,8 @@ static int bond_changelink(struct net_device *bond_dev,
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)
return err;
}
@ -199,7 +215,8 @@ static int bond_changelink(struct net_device *bond_dev,
int 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)
return err;
}
@ -212,7 +229,8 @@ static int bond_changelink(struct net_device *bond_dev,
if (dev)
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)
return err;
}
@ -220,7 +238,8 @@ static int bond_changelink(struct net_device *bond_dev,
int 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)
return err;
}
@ -228,7 +247,8 @@ static int bond_changelink(struct net_device *bond_dev,
int 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)
return err;
}
@ -236,7 +256,8 @@ static int bond_changelink(struct net_device *bond_dev,
int 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)
return err;
}
@ -244,7 +265,8 @@ static int bond_changelink(struct net_device *bond_dev,
int 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)
return err;
}
@ -252,7 +274,8 @@ static int bond_changelink(struct net_device *bond_dev,
int 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)
return err;
}
@ -260,8 +283,8 @@ static int bond_changelink(struct net_device *bond_dev,
int all_slaves_active =
nla_get_u8(data[IFLA_BOND_ALL_SLAVES_ACTIVE]);
err = bond_option_all_slaves_active_set(bond,
all_slaves_active);
bond_opt_initval(&newval, all_slaves_active);
err = __bond_opt_set(bond, BOND_OPT_ALL_SLAVES_ACTIVE, &newval);
if (err)
return err;
}
@ -269,7 +292,8 @@ static int bond_changelink(struct net_device *bond_dev,
int 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)
return err;
}
@ -277,7 +301,8 @@ static int bond_changelink(struct net_device *bond_dev,
int 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)
return err;
}
@ -285,8 +310,8 @@ static int bond_changelink(struct net_device *bond_dev,
int packets_per_slave =
nla_get_u32(data[IFLA_BOND_PACKETS_PER_SLAVE]);
err = bond_option_packets_per_slave_set(bond,
packets_per_slave);
bond_opt_initval(&newval, packets_per_slave);
err = __bond_opt_set(bond, BOND_OPT_PACKETS_PER_SLAVE, &newval);
if (err)
return err;
}
@ -294,7 +319,8 @@ static int bond_changelink(struct net_device *bond_dev,
int 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)
return err;
}
@ -302,7 +328,8 @@ static int bond_changelink(struct net_device *bond_dev,
int 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)
return err;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,170 @@
/*
* 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 */

View File

@ -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)
{
struct bonding *bond = seq->private;
struct bond_opt_value *optval;
struct slave *curr;
int i;
@ -76,26 +77,32 @@ static void bond_info_show_master(struct seq_file *seq)
bond_mode_name(bond->params.mode));
if (bond->params.mode == BOND_MODE_ACTIVEBACKUP &&
bond->params.fail_over_mac)
seq_printf(seq, " (fail_over_mac %s)",
fail_over_mac_tbl[bond->params.fail_over_mac].modename);
bond->params.fail_over_mac) {
optval = bond_opt_get_val(BOND_OPT_FAIL_OVER_MAC,
bond->params.fail_over_mac);
seq_printf(seq, " (fail_over_mac %s)", optval->string);
}
seq_printf(seq, "\n");
if (bond->params.mode == BOND_MODE_XOR ||
bond->params.mode == BOND_MODE_8023AD) {
optval = bond_opt_get_val(BOND_OPT_XMIT_HASH,
bond->params.xmit_policy);
seq_printf(seq, "Transmit Hash Policy: %s (%d)\n",
xmit_hashtype_tbl[bond->params.xmit_policy].modename,
bond->params.xmit_policy);
optval->string, bond->params.xmit_policy);
}
if (USES_PRIMARY(bond->params.mode)) {
seq_printf(seq, "Primary Slave: %s",
(bond->primary_slave) ?
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)",
pri_reselect_tbl[bond->params.primary_reselect].modename);
optval->string);
}
seq_printf(seq, "\nCurrently Active Slave: %s\n",
(curr) ? curr->dev->name : "None");
@ -136,8 +143,10 @@ static void bond_info_show_master(struct seq_file *seq)
seq_printf(seq, "LACP rate: %s\n",
(bond->params.lacp_fast) ? "fast" : "slow");
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",
ad_select_tbl[bond->params.ad_select].modename);
optval->string);
if (__bond_3ad_get_active_agg_info(bond, &ad_info)) {
seq_printf(seq, "bond %s has no active aggregator\n",

View File

@ -200,58 +200,15 @@ static ssize_t bonding_store_slaves(struct device *d,
struct device_attribute *attr,
const char *buffer, size_t count)
{
char command[IFNAMSIZ + 1] = { 0, };
char *ifname;
int res, ret = count;
struct net_device *dev;
struct bonding *bond = to_bond(d);
int ret;
if (!rtnl_trylock())
return restart_syscall();
ret = bond_opt_tryset_rtnl(bond, BOND_OPT_SLAVES, (char *)buffer);
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;
}
static DEVICE_ATTR(slaves, S_IRUGO | S_IWUSR, bonding_show_slaves,
bonding_store_slaves);
@ -263,37 +220,24 @@ static ssize_t bonding_show_mode(struct device *d,
struct device_attribute *attr, char *buf)
{
struct bonding *bond = to_bond(d);
struct bond_opt_value *val;
return sprintf(buf, "%s %d\n",
bond_mode_tbl[bond->params.mode].modename,
bond->params.mode);
val = bond_opt_get_val(BOND_OPT_MODE, bond->params.mode);
return sprintf(buf, "%s %d\n", val->string, bond->params.mode);
}
static ssize_t bonding_store_mode(struct device *d,
struct device_attribute *attr,
const char *buf, size_t count)
{
int new_value, ret;
struct bonding *bond = to_bond(d);
int ret;
new_value = bond_parse_parm(buf, bond_mode_tbl);
if (new_value < 0) {
pr_err("%s: Ignoring invalid mode value %.*s.\n",
bond->dev->name, (int)strlen(buf) - 1, buf);
return -EINVAL;
}
if (!rtnl_trylock())
return restart_syscall();
ret = bond_option_mode_set(bond, new_value);
if (!ret) {
pr_info("%s: setting mode to %s (%d).\n",
bond->dev->name, bond_mode_tbl[new_value].modename,
new_value);
ret = bond_opt_tryset_rtnl(bond, BOND_OPT_MODE, (char *)buf);
if (!ret)
ret = count;
}
rtnl_unlock();
return ret;
}
static DEVICE_ATTR(mode, S_IRUGO | S_IWUSR,
@ -307,35 +251,24 @@ static ssize_t bonding_show_xmit_hash(struct device *d,
char *buf)
{
struct bonding *bond = to_bond(d);
struct bond_opt_value *val;
return sprintf(buf, "%s %d\n",
xmit_hashtype_tbl[bond->params.xmit_policy].modename,
bond->params.xmit_policy);
val = bond_opt_get_val(BOND_OPT_XMIT_HASH, bond->params.xmit_policy);
return sprintf(buf, "%s %d\n", val->string, bond->params.xmit_policy);
}
static ssize_t bonding_store_xmit_hash(struct device *d,
struct device_attribute *attr,
const char *buf, size_t count)
{
int new_value, ret;
struct bonding *bond = to_bond(d);
int ret;
new_value = bond_parse_parm(buf, xmit_hashtype_tbl);
if (new_value < 0) {
pr_err("%s: Ignoring invalid xmit hash policy value %.*s.\n",
bond->dev->name,
(int)strlen(buf) - 1, buf);
return -EINVAL;
}
if (!rtnl_trylock())
return restart_syscall();
ret = bond_option_xmit_hash_policy_set(bond, new_value);
ret = bond_opt_tryset_rtnl(bond, BOND_OPT_XMIT_HASH, (char *)buf);
if (!ret)
ret = count;
rtnl_unlock();
return ret;
}
static DEVICE_ATTR(xmit_hash_policy, S_IRUGO | S_IWUSR,
@ -349,10 +282,12 @@ static ssize_t bonding_show_arp_validate(struct device *d,
char *buf)
{
struct bonding *bond = to_bond(d);
struct bond_opt_value *val;
return sprintf(buf, "%s %d\n",
arp_validate_tbl[bond->params.arp_validate].modename,
bond->params.arp_validate);
val = bond_opt_get_val(BOND_OPT_ARP_VALIDATE,
bond->params.arp_validate);
return sprintf(buf, "%s %d\n", val->string, bond->params.arp_validate);
}
static ssize_t bonding_store_arp_validate(struct device *d,
@ -360,23 +295,12 @@ static ssize_t bonding_store_arp_validate(struct device *d,
const char *buf, size_t count)
{
struct bonding *bond = to_bond(d);
int new_value, ret;
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)
ret = count;
rtnl_unlock();
return ret;
}
@ -390,10 +314,12 @@ static ssize_t bonding_show_arp_all_targets(struct device *d,
char *buf)
{
struct bonding *bond = to_bond(d);
int value = bond->params.arp_all_targets;
struct bond_opt_value *val;
return sprintf(buf, "%s %d\n", arp_all_targets_tbl[value].modename,
value);
val = bond_opt_get_val(BOND_OPT_ARP_ALL_TARGETS,
bond->params.arp_all_targets);
return sprintf(buf, "%s %d\n",
val->string, bond->params.arp_all_targets);
}
static ssize_t bonding_store_arp_all_targets(struct device *d,
@ -401,24 +327,12 @@ static ssize_t bonding_store_arp_all_targets(struct device *d,
const char *buf, size_t count)
{
struct bonding *bond = to_bond(d);
int new_value, 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)
ret = count;
rtnl_unlock();
return ret;
}
@ -434,34 +348,25 @@ static ssize_t bonding_show_fail_over_mac(struct device *d,
char *buf)
{
struct bonding *bond = to_bond(d);
struct bond_opt_value *val;
return sprintf(buf, "%s %d\n",
fail_over_mac_tbl[bond->params.fail_over_mac].modename,
bond->params.fail_over_mac);
val = bond_opt_get_val(BOND_OPT_FAIL_OVER_MAC,
bond->params.fail_over_mac);
return sprintf(buf, "%s %d\n", val->string, bond->params.fail_over_mac);
}
static ssize_t bonding_store_fail_over_mac(struct device *d,
struct device_attribute *attr,
const char *buf, size_t count)
{
int new_value, ret;
struct bonding *bond = to_bond(d);
int ret;
new_value = bond_parse_parm(buf, fail_over_mac_tbl);
if (new_value < 0) {
pr_err("%s: Ignoring invalid fail_over_mac value %s.\n",
bond->dev->name, buf);
return -EINVAL;
}
if (!rtnl_trylock())
return restart_syscall();
ret = bond_option_fail_over_mac_set(bond, new_value);
ret = bond_opt_tryset_rtnl(bond, BOND_OPT_FAIL_OVER_MAC, (char *)buf);
if (!ret)
ret = count;
rtnl_unlock();
return ret;
}
@ -488,22 +393,12 @@ static ssize_t bonding_store_arp_interval(struct device *d,
const char *buf, size_t count)
{
struct bonding *bond = to_bond(d);
int new_value, ret;
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)
ret = count;
rtnl_unlock();
return ret;
}
static DEVICE_ATTR(arp_interval, S_IRUGO | S_IWUSR,
@ -516,8 +411,8 @@ static ssize_t bonding_show_arp_targets(struct device *d,
struct device_attribute *attr,
char *buf)
{
int i, res = 0;
struct bonding *bond = to_bond(d);
int i, res = 0;
for (i = 0; i < BOND_MAX_ARP_TARGETS; i++) {
if (bond->params.arp_targets[i])
@ -526,6 +421,7 @@ static ssize_t bonding_show_arp_targets(struct device *d,
}
if (res)
buf[res-1] = '\n'; /* eat the leftover space */
return res;
}
@ -534,30 +430,12 @@ static ssize_t bonding_store_arp_targets(struct device *d,
const char *buf, size_t count)
{
struct bonding *bond = to_bond(d);
__be32 target;
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);
int ret;
ret = bond_opt_tryset_rtnl(bond, BOND_OPT_ARP_TARGETS, (char *)buf);
if (!ret)
ret = count;
rtnl_unlock();
return ret;
}
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,
struct device_attribute *attr,
const char *buf, size_t count)
{
int new_value, ret;
struct bonding *bond = to_bond(d);
int ret;
if (sscanf(buf, "%d", &new_value) != 1) {
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);
ret = bond_opt_tryset_rtnl(bond, BOND_OPT_DOWNDELAY, (char *)buf);
if (!ret)
ret = count;
rtnl_unlock();
return ret;
}
static DEVICE_ATTR(downdelay, S_IRUGO | S_IWUSR,
@ -615,23 +484,13 @@ static ssize_t bonding_store_updelay(struct device *d,
struct device_attribute *attr,
const char *buf, size_t count)
{
int new_value, ret;
struct bonding *bond = to_bond(d);
int ret;
if (sscanf(buf, "%d", &new_value) != 1) {
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);
ret = bond_opt_tryset_rtnl(bond, BOND_OPT_UPDELAY, (char *)buf);
if (!ret)
ret = count;
rtnl_unlock();
return ret;
}
static DEVICE_ATTR(updelay, S_IRUGO | S_IWUSR,
@ -646,10 +505,11 @@ static ssize_t bonding_show_lacp(struct device *d,
char *buf)
{
struct bonding *bond = to_bond(d);
struct bond_opt_value *val;
return sprintf(buf, "%s %d\n",
bond_lacp_tbl[bond->params.lacp_fast].modename,
bond->params.lacp_fast);
val = bond_opt_get_val(BOND_OPT_LACP_RATE, bond->params.lacp_fast);
return sprintf(buf, "%s %d\n", val->string, bond->params.lacp_fast);
}
static ssize_t bonding_store_lacp(struct device *d,
@ -657,23 +517,12 @@ static ssize_t bonding_store_lacp(struct device *d,
const char *buf, size_t count)
{
struct bonding *bond = to_bond(d);
int new_value, ret;
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)
ret = count;
rtnl_unlock();
return ret;
}
static DEVICE_ATTR(lacp_rate, S_IRUGO | S_IWUSR,
@ -694,23 +543,11 @@ static ssize_t bonding_store_min_links(struct device *d,
{
struct bonding *bond = to_bond(d);
int ret;
unsigned int new_value;
ret = kstrtouint(buf, 0, &new_value);
if (ret < 0) {
pr_err("%s: Ignoring invalid min links value %s.\n",
bond->dev->name, buf);
return ret;
}
if (!rtnl_trylock())
return restart_syscall();
ret = bond_option_min_links_set(bond, new_value);
ret = bond_opt_tryset_rtnl(bond, BOND_OPT_MINLINKS, (char *)buf);
if (!ret)
ret = count;
rtnl_unlock();
return ret;
}
static DEVICE_ATTR(min_links, S_IRUGO | S_IWUSR,
@ -721,10 +558,11 @@ static ssize_t bonding_show_ad_select(struct device *d,
char *buf)
{
struct bonding *bond = to_bond(d);
struct bond_opt_value *val;
return sprintf(buf, "%s %d\n",
ad_select_tbl[bond->params.ad_select].modename,
bond->params.ad_select);
val = bond_opt_get_val(BOND_OPT_AD_SELECT, bond->params.ad_select);
return sprintf(buf, "%s %d\n", val->string, bond->params.ad_select);
}
@ -732,24 +570,13 @@ static ssize_t bonding_store_ad_select(struct device *d,
struct device_attribute *attr,
const char *buf, size_t count)
{
int new_value, ret;
struct bonding *bond = to_bond(d);
int ret;
new_value = bond_parse_parm(buf, ad_select_tbl);
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);
ret = bond_opt_tryset_rtnl(bond, BOND_OPT_AD_SELECT, (char *)buf);
if (!ret)
ret = count;
rtnl_unlock();
return ret;
}
static DEVICE_ATTR(ad_select, S_IRUGO | S_IWUSR,
@ -771,24 +598,12 @@ static ssize_t bonding_store_num_peer_notif(struct device *d,
const char *buf, size_t count)
{
struct bonding *bond = to_bond(d);
u8 new_value;
int ret;
ret = kstrtou8(buf, 10, &new_value);
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);
ret = bond_opt_tryset_rtnl(bond, BOND_OPT_NUM_PEER_NOTIF, (char *)buf);
if (!ret)
ret = count;
rtnl_unlock();
return ret;
}
static DEVICE_ATTR(num_grat_arp, S_IRUGO | S_IWUSR,
@ -815,23 +630,13 @@ static ssize_t bonding_store_miimon(struct device *d,
struct device_attribute *attr,
const char *buf, size_t count)
{
int new_value, ret;
struct bonding *bond = to_bond(d);
int ret;
if (sscanf(buf, "%d", &new_value) != 1) {
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);
ret = bond_opt_tryset_rtnl(bond, BOND_OPT_MIIMON, (char *)buf);
if (!ret)
ret = count;
rtnl_unlock();
return ret;
}
static DEVICE_ATTR(miimon, S_IRUGO | S_IWUSR,
@ -862,21 +667,12 @@ static ssize_t bonding_store_primary(struct device *d,
const char *buf, size_t count)
{
struct bonding *bond = to_bond(d);
char ifname[IFNAMSIZ];
int ret;
sscanf(buf, "%15s", ifname); /* IFNAMSIZ */
if (ifname[0] == '\n')
ifname[0] = '\0';
if (!rtnl_trylock())
return restart_syscall();
ret = bond_option_primary_set(bond, ifname);
ret = bond_opt_tryset_rtnl(bond, BOND_OPT_PRIMARY, (char *)buf);
if (!ret)
ret = count;
rtnl_unlock();
return ret;
}
static DEVICE_ATTR(primary, S_IRUGO | S_IWUSR,
@ -890,35 +686,27 @@ static ssize_t bonding_show_primary_reselect(struct device *d,
char *buf)
{
struct bonding *bond = to_bond(d);
struct bond_opt_value *val;
val = bond_opt_get_val(BOND_OPT_PRIMARY_RESELECT,
bond->params.primary_reselect);
return sprintf(buf, "%s %d\n",
pri_reselect_tbl[bond->params.primary_reselect].modename,
bond->params.primary_reselect);
val->string, bond->params.primary_reselect);
}
static ssize_t bonding_store_primary_reselect(struct device *d,
struct device_attribute *attr,
const char *buf, size_t count)
{
int new_value, ret;
struct bonding *bond = to_bond(d);
int ret;
new_value = bond_parse_parm(buf, pri_reselect_tbl);
if (new_value < 0) {
pr_err("%s: Ignoring invalid primary_reselect value %.*s.\n",
bond->dev->name,
(int) strlen(buf) - 1, buf);
return -EINVAL;
}
if (!rtnl_trylock())
return restart_syscall();
ret = bond_option_primary_reselect_set(bond, new_value);
ret = bond_opt_tryset_rtnl(bond, BOND_OPT_PRIMARY_RESELECT,
(char *)buf);
if (!ret)
ret = count;
rtnl_unlock();
return ret;
}
static DEVICE_ATTR(primary_reselect, S_IRUGO | S_IWUSR,
@ -941,23 +729,13 @@ static ssize_t bonding_store_carrier(struct device *d,
struct device_attribute *attr,
const char *buf, size_t count)
{
int new_value, ret;
struct bonding *bond = to_bond(d);
int ret;
if (sscanf(buf, "%d", &new_value) != 1) {
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);
ret = bond_opt_tryset_rtnl(bond, BOND_OPT_USE_CARRIER, (char *)buf);
if (!ret)
ret = count;
rtnl_unlock();
return ret;
}
static DEVICE_ATTR(use_carrier, S_IRUGO | S_IWUSR,
@ -988,34 +766,14 @@ static ssize_t bonding_store_active_slave(struct device *d,
struct device_attribute *attr,
const char *buf, size_t count)
{
int ret;
struct bonding *bond = to_bond(d);
char ifname[IFNAMSIZ];
struct net_device *dev;
int ret;
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)
ret = count;
out:
rtnl_unlock();
return ret;
}
static DEVICE_ATTR(active_slave, S_IRUGO | S_IWUSR,
bonding_show_active_slave, bonding_store_active_slave);
@ -1184,72 +942,15 @@ static ssize_t bonding_store_queue_id(struct device *d,
struct device_attribute *attr,
const char *buffer, size_t count)
{
struct slave *slave, *update_slave;
struct bonding *bond = to_bond(d);
struct list_head *iter;
u16 qid;
int ret = count;
char *delim;
struct net_device *sdev = NULL;
int ret;
if (!rtnl_trylock())
return restart_syscall();
ret = bond_opt_tryset_rtnl(bond, BOND_OPT_QUEUE_ID, (char *)buffer);
if (!ret)
ret = count;
/* 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 */
update_slave->queue_id = qid;
out:
rtnl_unlock();
return ret;
err_no_cmd:
pr_info("invalid input for queue_id set for %s.\n",
bond->dev->name);
ret = -EPERM;
goto out;
}
static DEVICE_ATTR(queue_id, S_IRUGO | S_IWUSR, bonding_show_queue_id,
bonding_store_queue_id);
@ -1271,22 +972,13 @@ static ssize_t bonding_store_slaves_active(struct device *d,
const char *buf, size_t count)
{
struct bonding *bond = to_bond(d);
int new_value, ret;
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)
ret = count;
rtnl_unlock();
return ret;
}
static DEVICE_ATTR(all_slaves_active, S_IRUGO | S_IWUSR,
@ -1308,23 +1000,13 @@ static ssize_t bonding_store_resend_igmp(struct device *d,
struct device_attribute *attr,
const char *buf, size_t count)
{
int new_value, ret = count;
struct bonding *bond = to_bond(d);
int ret;
if (sscanf(buf, "%d", &new_value) != 1) {
pr_err("%s: no resend_igmp value specified.\n",
bond->dev->name);
return -EINVAL;
}
if (!rtnl_trylock())
return restart_syscall();
ret = bond_option_resend_igmp_set(bond, new_value);
ret = bond_opt_tryset_rtnl(bond, BOND_OPT_RESEND_IGMP, (char *)buf);
if (!ret)
ret = count;
rtnl_unlock();
return ret;
}
@ -1345,22 +1027,12 @@ static ssize_t bonding_store_lp_interval(struct device *d,
const char *buf, size_t count)
{
struct bonding *bond = to_bond(d);
int new_value, ret;
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)
ret = count;
rtnl_unlock();
return ret;
}
@ -1381,22 +1053,13 @@ static ssize_t bonding_store_packets_per_slave(struct device *d,
const char *buf, size_t count)
{
struct bonding *bond = to_bond(d);
int new_value, ret;
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)
ret = count;
rtnl_unlock();
return ret;
}

View File

@ -27,6 +27,7 @@
#include "bond_3ad.h"
#include "bond_alb.h"
#include "bond_options.h"
#define DRV_VERSION "3.7.1"
#define DRV_RELDATE "April 27, 2011"
@ -451,35 +452,8 @@ void bond_setup(struct net_device *bond_dev);
unsigned int bond_get_num_tx_queues(void);
int bond_netlink_init(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_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(struct bonding *bond);
const char *bond_slave_link_status(s8 link);
@ -562,7 +536,6 @@ static inline int bond_get_targets_ip(__be32 *targets, __be32 ip)
/* exported from bond_main.c */
extern int bond_net_id;
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 arp_validate_tbl[];
extern const struct bond_parm_tbl arp_all_targets_tbl[];