diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index f100bd958b88..2ca949f6e995 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -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 { diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c index e8526552790c..a8fa7256b7b1 100644 --- a/drivers/net/bonding/bond_netlink.c +++ b/drivers/net/bonding/bond_netlink.c @@ -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; } diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c index 85e434886f2e..05a402c99bff 100644 --- a/drivers/net/bonding/bond_options.c +++ b/drivers/net/bonding/bond_options.c @@ -16,31 +16,575 @@ #include #include #include +#include +#include #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) { - pr_err("%s: Ignoring invalid mode value %d.\n", - bond->dev->name, mode); - return -EINVAL; + struct bond_option *opt; + int i; + + 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) { - pr_err("%s: unable to update mode because interface is up.\n", - bond->dev->name); - return -EPERM; - } + for (i = 0; tbl[i].string; i++) { + /* Check for exact match */ + if (checkval) { + if (val->value == tbl[i].value) + ret = &tbl[i]; + } else { + if (!strcmp(valstr, "default") && + (tbl[i].flags & BOND_VALFLAG_DEFAULT)) + ret = &tbl[i]; - if (bond_has_slaves(bond)) { - pr_err("%s: unable to update mode because bond has slaves.\n", - bond->dev->name); - return -EPERM; + 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_NO_USES_ARP(mode) && bond->params.arp_interval) { +/* Check opt's dependencies against bond mode and currently set options */ +static int bond_opt_check_deps(struct bonding *bond, + const struct bond_option *opt) +{ + 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; +} + +/** + * 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", - bond->dev->name, bond_mode_tbl[mode].modename); + bond->dev->name, newval->string); /* disable arp monitoring */ bond->params.arp_interval = 0; /* set miimon to default value */ @@ -51,7 +595,8 @@ int bond_option_mode_set(struct bonding *bond, int mode) /* don't cache arp_validate between modes */ bond->params.arp_validate = BOND_ARP_VALIDATE_NONE; - bond->params.mode = mode; + bond->params.mode = newval->value; + return 0; } @@ -74,10 +619,21 @@ struct net_device *bond_option_active_slave_get(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; + 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 (!netif_is_bond_slave(slave_dev)) { pr_err("Device %s is not bonding slave.\n", @@ -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(); write_lock_bh(&bond->curr_slave_lock); @@ -134,19 +684,15 @@ int bond_option_active_slave_set(struct bonding *bond, write_unlock_bh(&bond->curr_slave_lock); unblock_netpoll_tx(); + 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_err("%s: Invalid miimon value %d not in range %d-%d; rejected.\n", - bond->dev->name, miimon, 0, INT_MAX); - return -EINVAL; - } - pr_info("%s: Setting MII monitoring interval to %d.\n", - bond->dev->name, miimon); - bond->params.miimon = miimon; + pr_info("%s: Setting MII monitoring interval to %llu.\n", + bond->dev->name, newval->value); + bond->params.miimon = newval->value; if (bond->params.updelay) pr_info("%s: Note: Updating updelay (to %d) since it is a multiple of the miimon value.\n", bond->dev->name, @@ -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", bond->dev->name, 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", bond->dev->name); bond->params.arp_interval = 0; @@ -168,104 +714,79 @@ int bond_option_miimon_set(struct bonding *bond, int miimon) * timer will get fired off when the open function * is called. */ - if (!miimon) { + if (!newval->value) { cancel_delayed_work_sync(&bond->mii_work); } else { cancel_delayed_work_sync(&bond->arp_work); queue_delayed_work(bond->wq, &bond->mii_work, 0); } } + 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", bond->dev->name); return -EPERM; } - - if (updelay < 0) { - pr_err("%s: Invalid up delay value %d not in range %d-%d; rejected.\n", - 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, - (updelay / bond->params.miimon) * - bond->params.miimon); - } - bond->params.updelay = updelay / bond->params.miimon; - pr_info("%s: Setting up delay to %d.\n", - bond->dev->name, - bond->params.updelay * bond->params.miimon); + if ((newval->value % bond->params.miimon) != 0) { + pr_warn("%s: Warning: up delay (%llu) is not a multiple of miimon (%d), updelay rounded to %llu ms\n", + bond->dev->name, newval->value, + bond->params.miimon, + (newval->value / bond->params.miimon) * + bond->params.miimon); } + bond->params.updelay = newval->value / bond->params.miimon; + pr_info("%s: Setting up delay to %d.\n", + bond->dev->name, + bond->params.updelay * bond->params.miimon); 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", bond->dev->name); return -EPERM; } - - if (downdelay < 0) { - pr_err("%s: Invalid down delay value %d not in range %d-%d; rejected.\n", - 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, - (downdelay / bond->params.miimon) * - bond->params.miimon); - } - bond->params.downdelay = downdelay / bond->params.miimon; - pr_info("%s: Setting down delay to %d.\n", - bond->dev->name, - bond->params.downdelay * bond->params.miimon); + if ((newval->value % bond->params.miimon) != 0) { + pr_warn("%s: Warning: down delay (%llu) is not a multiple of miimon (%d), delay rounded to %llu ms\n", + bond->dev->name, newval->value, + bond->params.miimon, + (newval->value / bond->params.miimon) * + bond->params.miimon); } + bond->params.downdelay = newval->value / bond->params.miimon; + pr_info("%s: Setting down delay to %d.\n", + bond->dev->name, + bond->params.downdelay * bond->params.miimon); 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)) { - bond->params.use_carrier = use_carrier; - pr_info("%s: Setting use_carrier to %d.\n", - bond->dev->name, use_carrier); - } else { - pr_info("%s: Ignoring invalid use_carrier value %d.\n", - bond->dev->name, use_carrier); - } + pr_info("%s: Setting use_carrier to %llu.\n", + bond->dev->name, newval->value); + bond->params.use_carrier = newval->value; 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_err("%s: Invalid arp_interval value %d not in range 0-%d; rejected.\n", - bond->dev->name, arp_interval, INT_MAX); - return -EINVAL; - } - 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) { + pr_info("%s: Setting ARP monitoring interval to %llu.\n", + bond->dev->name, newval->value); + bond->params.arp_interval = newval->value; + if (newval->value) { if (bond->params.miimon) { pr_info("%s: ARP monitoring cannot be used with MII monitoring. %s Disabling MII monitoring.\n", bond->dev->name, bond->dev->name); @@ -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 * is called. */ - if (!arp_interval) { + if (!newval->value) { if (bond->params.arp_validate) bond->recv_probe = NULL; cancel_delayed_work_sync(&bond->arp_work); @@ -401,95 +922,84 @@ int bond_option_arp_ip_target_rem(struct bonding *bond, __be32 target) return 0; } -int bond_option_arp_ip_targets_set(struct bonding *bond, __be32 *targets, - int count) +void bond_option_arp_ip_targets_clear(struct bonding *bond) { - int i, ret = 0; + int i; /* not to race with bond_arp_rcv */ write_lock_bh(&bond->lock); - - /* clear table */ for (i = 0; i < BOND_MAX_ARP_TARGETS; i++) _bond_options_arp_ip_target_set(bond, i, 0, 0); + write_unlock_bh(&bond->lock); +} - if (count == 0 && bond->params.arp_interval) - pr_warn("%s: removing last arp target with arp_interval on\n", - bond->dev->name); +int bond_option_arp_ip_targets_set(struct bonding *bond, + struct bond_opt_value *newval) +{ + int ret = -EPERM; + __be32 target; - for (i = 0; i < count; i++) { - ret = _bond_option_arp_ip_target_add(bond, targets[i]); - if (ret) - break; + if (newval->string) { + 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 + or -.\n", + bond->dev->name); + } else { + target = newval->value; + ret = bond_option_arp_ip_target_add(bond, target); } - write_unlock_bh(&bond->lock); return ret; } -int bond_option_arp_validate_set(struct bonding *bond, int arp_validate) +int bond_option_arp_validate_set(struct bonding *bond, + struct bond_opt_value *newval) { - if (bond_parm_tbl_lookup(arp_validate, arp_validate_tbl) < 0) { - pr_err("%s: Ignoring invalid arp_validate value %d.\n", - bond->dev->name, arp_validate); - return -EINVAL; - } - - if (bond->params.mode != BOND_MODE_ACTIVEBACKUP) { - pr_err("%s: arp_validate only supported in active-backup mode.\n", - bond->dev->name); - return -EINVAL; - } - - pr_info("%s: setting arp_validate to %s (%d).\n", - bond->dev->name, arp_validate_tbl[arp_validate].modename, - arp_validate); + pr_info("%s: setting arp_validate to %s (%llu).\n", + bond->dev->name, newval->string, newval->value); if (bond->dev->flags & IFF_UP) { - if (!arp_validate) + if (!newval->value) bond->recv_probe = NULL; else if (bond->params.arp_interval) bond->recv_probe = bond_arp_rcv; } - bond->params.arp_validate = arp_validate; + bond->params.arp_validate = newval->value; 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_err("%s: Ignoring invalid arp_all_targets value %d.\n", - bond->dev->name, arp_all_targets); - 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; + pr_info("%s: setting arp_all_targets to %s (%llu).\n", + bond->dev->name, newval->string, newval->value); + bond->params.arp_all_targets = newval->value; 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 slave *slave; - int err = 0; block_netpoll_tx(); read_lock(&bond->lock); write_lock_bh(&bond->curr_slave_lock); - if (!USES_PRIMARY(bond->params.mode)) { - pr_err("%s: Unable to set primary slave; %s is in mode %d\n", - bond->dev->name, bond->dev->name, bond->params.mode); - err = -EINVAL; - goto out; - } - + p = strchr(primary, '\n'); + if (p) + *p = '\0'; /* check to see if we are clearing primary */ if (!strlen(primary)) { pr_info("%s: Setting primary slave to None.\n", @@ -522,21 +1032,15 @@ out: read_unlock(&bond->lock); 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_err("%s: Ignoring invalid primary_reselect value %d.\n", - bond->dev->name, primary_reselect); - 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); + pr_info("%s: setting primary_reselect to %s (%llu).\n", + bond->dev->name, newval->string, newval->value); + bond->params.primary_reselect = newval->value; block_netpoll_tx(); write_lock_bh(&bond->curr_slave_lock); @@ -547,85 +1051,56 @@ int bond_option_primary_reselect_set(struct bonding *bond, int primary_reselect) 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_err("%s: Ignoring invalid fail_over_mac value %d.\n", - bond->dev->name, fail_over_mac); - 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); + pr_info("%s: Setting fail_over_mac to %s (%llu).\n", + bond->dev->name, newval->string, newval->value); + bond->params.fail_over_mac = newval->value; 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_err("%s: Ignoring invalid xmit_hash_policy value %d.\n", - bond->dev->name, xmit_hash_policy); - 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); + pr_info("%s: setting xmit hash policy to %s (%llu).\n", + bond->dev->name, newval->string, newval->value); + bond->params.xmit_policy = newval->value; 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_err("%s: Invalid resend_igmp value %d not in range 0-255; rejected.\n", - bond->dev->name, resend_igmp); - return -EINVAL; - } - - bond->params.resend_igmp = resend_igmp; - pr_info("%s: Setting resend_igmp to %d.\n", - bond->dev->name, resend_igmp); + pr_info("%s: Setting resend_igmp to %llu.\n", + bond->dev->name, newval->value); + bond->params.resend_igmp = newval->value; 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; } int bond_option_all_slaves_active_set(struct bonding *bond, - int all_slaves_active) + struct bond_opt_value *newval) { struct list_head *iter; struct slave *slave; - if (all_slaves_active == bond->params.all_slaves_active) + if (newval->value == bond->params.all_slaves_active) return 0; - - 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->params.all_slaves_active = newval->value; bond_for_each_slave(bond, slave, iter) { if (!bond_is_active_slave(slave)) { - if (all_slaves_active) + if (newval->value) slave->inactive = 0; else slave->inactive = 1; @@ -635,45 +1110,30 @@ int bond_option_all_slaves_active_set(struct bonding *bond, 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", - bond->dev->name, min_links); - bond->params.min_links = min_links; + pr_info("%s: Setting min links value to %llu\n", + bond->dev->name, newval->value); + bond->params.min_links = newval->value; 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) { - 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; + bond->params.lp_interval = newval->value; return 0; } -int bond_option_packets_per_slave_set(struct bonding *bond, - int packets_per_slave) +int bond_option_pps_set(struct bonding *bond, struct bond_opt_value *newval) { - if (packets_per_slave < 0 || packets_per_slave > USHRT_MAX) { - pr_err("%s: packets_per_slave must be between 0 and %u\n", - 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.packets_per_slave = newval->value; + if (newval->value > 0) { bond->params.reciprocal_packets_per_slave = - reciprocal_value(packets_per_slave); + reciprocal_value(newval->value); } else { /* reciprocal_packets_per_slave is unused if * packets_per_slave is 0 or 1, just initialize it @@ -685,53 +1145,132 @@ int bond_option_packets_per_slave_set(struct bonding *bond, 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_err("%s: Ignoring invalid LACP rate value %d.\n", - bond->dev->name, lacp_rate); - return -EINVAL; - } - - 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) { - 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; + pr_info("%s: Setting LACP rate to %s (%llu).\n", + bond->dev->name, newval->string, newval->value); + bond->params.lacp_fast = newval->value; bond_3ad_update_lacp_rate(bond); - pr_info("%s: Setting LACP rate to %s (%d).\n", - bond->dev->name, bond_lacp_tbl[lacp_rate].modename, - lacp_rate); return 0; } -int bond_option_ad_select_set(struct bonding *bond, int ad_select) +int bond_option_ad_select_set(struct bonding *bond, + struct bond_opt_value *newval) { - if (bond_parm_tbl_lookup(ad_select, ad_select_tbl) < 0) { - pr_err("%s: Ignoring invalid ad_select value %d.\n", - bond->dev->name, ad_select); - return -EINVAL; - } - - if (bond->dev->flags & IFF_UP) { - pr_err("%s: Unable to update ad_select because interface is up.\n", - bond->dev->name); - return -EPERM; - } - - bond->params.ad_select = ad_select; - pr_info("%s: Setting ad_select to %s (%d).\n", - bond->dev->name, ad_select_tbl[ad_select].modename, - ad_select); + pr_info("%s: Setting ad_select to %s (%llu).\n", + bond->dev->name, newval->string, newval->value); + bond->params.ad_select = newval->value; return 0; } + +int bond_option_queue_id_set(struct bonding *bond, + struct bond_opt_value *newval) +{ + struct slave *slave, *update_slave; + struct net_device *sdev; + struct list_head *iter; + 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 (!update_slave) + 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); + 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; + } + + switch (command[0]) { + case '+': + pr_info("%s: Adding slave %s.\n", bond->dev->name, dev->name); + ret = bond_enslave(bond->dev, dev); + break; + + 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; +} diff --git a/drivers/net/bonding/bond_options.h b/drivers/net/bonding/bond_options.h new file mode 100644 index 000000000000..433d37f6940b --- /dev/null +++ b/drivers/net/bonding/bond_options.h @@ -0,0 +1,170 @@ +/* + * drivers/net/bond/bond_options.h - bonding options + * Copyright (c) 2013 Nikolay Aleksandrov + * + * 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 */ diff --git a/drivers/net/bonding/bond_procfs.c b/drivers/net/bonding/bond_procfs.c index 8515b3442583..3ac20e78eafc 100644 --- a/drivers/net/bonding/bond_procfs.c +++ b/drivers/net/bonding/bond_procfs.c @@ -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", diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index c083e9a66ece..643fcc110299 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -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 + or -.\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; } diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index 0a616c41dc94..8032e07fec0e 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -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[];