diff options
author | David S. Miller <davem@davemloft.net> | 2014-01-04 06:03:27 +0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-01-04 06:03:27 +0400 |
commit | ffeed1beb62f3742693598dfe2f1c010de249bba (patch) | |
tree | 9b760e38d559ae6ac7611bc03e4b7f418cf2c7f4 | |
parent | baf42552c7c42c39a5a61c98ac655b40e6f96781 (diff) | |
parent | 3243c47b1abaa2653c62364f78212400556164c6 (diff) | |
download | linux-ffeed1beb62f3742693598dfe2f1c010de249bba.tar.xz |
Merge branch 'bonding'
Scott Feldman says:
====================
bonding: final set of netlink patches
v2:
- per Jiri's comment, fix ad_select checking against parm table by
spliting bond_parse_parm() into several funcs. Go ahead and apply
same technique to all parameters using parm table.
- fix netlink msg size to including missing nest attr
- drop the last patch for active_slaves. This patch needs to be
reworked per Jiri's comments and shouldn't hold up finalizing
the conversion of the existing parameter to netlink attributes.
Ding, assuming this patch set goes in, you should have all you
need to start converting module parameter setting/checking over to
funcs in *_options.c.
I'll send iproute2 patch for bonding netlink support once this patch
set is accepted.
v1:
The following series implements the last set of bonding netlink attributes
for 802.3ad mode:
lacp_rate
ad_select
ad_info, nest of:
ad_aggregator
ad_num_ports
ad_actor_key
ad_partner_key
ad_partner_mac
The last patch adds an additional netlink attribute, active_slaves, which
is a nested list of ifindices for current active slaves. We're using this
list to enable/disable hashing of ports in a hardware LAG implementation.
In the same way bonding driver includes/excludes ports for 802.3ad egress
hashing, hardware ports are included/excluded from egress hashing by
hardware based on port active status. Yes, data path offloaded to
hardware, control path remains in kernel via bonding driver.
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/bonding/bond_main.c | 45 | ||||
-rw-r--r-- | drivers/net/bonding/bond_netlink.c | 67 | ||||
-rw-r--r-- | drivers/net/bonding/bond_options.c | 96 | ||||
-rw-r--r-- | drivers/net/bonding/bond_sysfs.c | 69 | ||||
-rw-r--r-- | drivers/net/bonding/bonding.h | 3 | ||||
-rw-r--r-- | include/uapi/linux/if_link.h | 14 |
6 files changed, 221 insertions, 73 deletions
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 11bedbaf37db..e06c4453eabb 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -3933,6 +3933,29 @@ static void bond_uninit(struct net_device *bond_dev) /*------------------------- Module initialization ---------------------------*/ +int bond_parm_tbl_lookup(int mode, const struct bond_parm_tbl *tbl) +{ + int i; + + for (i = 0; tbl[i].modename; i++) + if (mode == tbl[i].mode) + return tbl[i].mode; + + return -1; +} + +static int bond_parm_tbl_lookup_name(const char *modename, + const struct bond_parm_tbl *tbl) +{ + int i; + + for (i = 0; tbl[i].modename; i++) + if (strcmp(modename, tbl[i].modename) == 0) + return tbl[i].mode; + + return -1; +} + /* * Convert string input module parms. Accept either the * number of the mode or its string name. A bit complicated because @@ -3941,27 +3964,17 @@ static void bond_uninit(struct net_device *bond_dev) */ int bond_parse_parm(const char *buf, const struct bond_parm_tbl *tbl) { - int modeint = -1, i, rv; - char *p, modestr[BOND_MAX_MODENAME_LEN + 1] = { 0, }; + int modeint; + char *p, modestr[BOND_MAX_MODENAME_LEN + 1]; for (p = (char *)buf; *p; p++) if (!(isdigit(*p) || isspace(*p))) break; - if (*p) - rv = sscanf(buf, "%20s", modestr); - else - rv = sscanf(buf, "%d", &modeint); - - if (!rv) - return -1; - - for (i = 0; tbl[i].modename; i++) { - if (modeint == tbl[i].mode) - return tbl[i].mode; - if (strcmp(modestr, tbl[i].modename) == 0) - return tbl[i].mode; - } + if (*p && sscanf(buf, "%20s", modestr) != 0) + return bond_parm_tbl_lookup_name(modestr, tbl); + else if (sscanf(buf, "%d", &modeint) != 0) + return bond_parm_tbl_lookup(modeint, tbl); return -1; } diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c index 84acd144d075..555c7837d8e6 100644 --- a/drivers/net/bonding/bond_netlink.c +++ b/drivers/net/bonding/bond_netlink.c @@ -43,6 +43,9 @@ static const struct nla_policy bond_policy[IFLA_BOND_MAX + 1] = { [IFLA_BOND_MIN_LINKS] = { .type = NLA_U32 }, [IFLA_BOND_LP_INTERVAL] = { .type = NLA_U32 }, [IFLA_BOND_PACKETS_PER_SLAVE] = { .type = NLA_U32 }, + [IFLA_BOND_AD_LACP_RATE] = { .type = NLA_U8 }, + [IFLA_BOND_AD_SELECT] = { .type = NLA_U8 }, + [IFLA_BOND_AD_INFO] = { .type = NLA_NESTED }, }; static int bond_validate(struct nlattr *tb[], struct nlattr *data[]) @@ -252,6 +255,22 @@ static int bond_changelink(struct net_device *bond_dev, if (err) return err; } + if (data[IFLA_BOND_AD_LACP_RATE]) { + int lacp_rate = + nla_get_u8(data[IFLA_BOND_AD_LACP_RATE]); + + err = bond_option_lacp_rate_set(bond, lacp_rate); + if (err) + return err; + } + if (data[IFLA_BOND_AD_SELECT]) { + int ad_select = + nla_get_u8(data[IFLA_BOND_AD_SELECT]); + + err = bond_option_ad_select_set(bond, ad_select); + if (err) + return err; + } return 0; } @@ -277,6 +296,7 @@ static size_t bond_get_size(const struct net_device *bond_dev) nla_total_size(sizeof(u8)) + /* IFLA_BOND_USE_CARRIER */ nla_total_size(sizeof(u32)) + /* IFLA_BOND_ARP_INTERVAL */ /* IFLA_BOND_ARP_IP_TARGET */ + nla_total_size(sizeof(struct nlattr)) + nla_total_size(sizeof(u32)) * BOND_MAX_ARP_TARGETS + nla_total_size(sizeof(u32)) + /* IFLA_BOND_ARP_VALIDATE */ nla_total_size(sizeof(u32)) + /* IFLA_BOND_ARP_ALL_TARGETS */ @@ -290,6 +310,14 @@ static size_t bond_get_size(const struct net_device *bond_dev) nla_total_size(sizeof(u32)) + /* IFLA_BOND_MIN_LINKS */ nla_total_size(sizeof(u32)) + /* IFLA_BOND_LP_INTERVAL */ nla_total_size(sizeof(u32)) + /* IFLA_BOND_PACKETS_PER_SLAVE */ + nla_total_size(sizeof(u8)) + /* IFLA_BOND_AD_LACP_RATE */ + nla_total_size(sizeof(u8)) + /* IFLA_BOND_AD_SELECT */ + nla_total_size(sizeof(struct nlattr)) + /* IFLA_BOND_AD_INFO */ + nla_total_size(sizeof(u16)) + /* IFLA_BOND_AD_INFO_AGGREGATOR */ + nla_total_size(sizeof(u16)) + /* IFLA_BOND_AD_INFO_NUM_PORTS */ + nla_total_size(sizeof(u16)) + /* IFLA_BOND_AD_INFO_ACTOR_KEY */ + nla_total_size(sizeof(u16)) + /* IFLA_BOND_AD_INFO_PARTNER_KEY*/ + nla_total_size(ETH_ALEN) + /* IFLA_BOND_AD_INFO_PARTNER_MAC*/ 0; } @@ -395,6 +423,45 @@ static int bond_fill_info(struct sk_buff *skb, packets_per_slave)) goto nla_put_failure; + if (nla_put_u8(skb, IFLA_BOND_AD_LACP_RATE, + bond->params.lacp_fast)) + goto nla_put_failure; + + if (nla_put_u8(skb, IFLA_BOND_AD_SELECT, + bond->params.ad_select)) + goto nla_put_failure; + + if (bond->params.mode == BOND_MODE_8023AD) { + struct ad_info info; + + if (!bond_3ad_get_active_agg_info(bond, &info)) { + struct nlattr *nest; + + nest = nla_nest_start(skb, IFLA_BOND_AD_INFO); + if (!nest) + goto nla_put_failure; + + if (nla_put_u16(skb, IFLA_BOND_AD_INFO_AGGREGATOR, + info.aggregator_id)) + goto nla_put_failure; + if (nla_put_u16(skb, IFLA_BOND_AD_INFO_NUM_PORTS, + info.ports)) + goto nla_put_failure; + if (nla_put_u16(skb, IFLA_BOND_AD_INFO_ACTOR_KEY, + info.actor_key)) + goto nla_put_failure; + if (nla_put_u16(skb, IFLA_BOND_AD_INFO_PARTNER_KEY, + info.partner_key)) + goto nla_put_failure; + if (nla_put(skb, IFLA_BOND_AD_INFO_PARTNER_MAC, + sizeof(info.partner_system), + &info.partner_system)) + goto nla_put_failure; + + nla_nest_end(skb, nest); + } + } + return 0; nla_put_failure: diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c index f8a2cd8c7b57..945a6668da83 100644 --- a/drivers/net/bonding/bond_options.c +++ b/drivers/net/bonding/bond_options.c @@ -19,19 +19,11 @@ #include <linux/reciprocal_div.h> #include "bonding.h" -static bool bond_mode_is_valid(int mode) -{ - int i; - - for (i = 0; bond_mode_tbl[i].modename; i++); - - return mode >= 0 && mode < i; -} - int bond_option_mode_set(struct bonding *bond, int mode) { - if (!bond_mode_is_valid(mode)) { - pr_err("invalid mode value %d.\n", mode); + 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; } @@ -438,11 +430,18 @@ int bond_option_arp_ip_targets_set(struct bonding *bond, __be32 *targets, int bond_option_arp_validate_set(struct bonding *bond, int arp_validate) { + 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); @@ -460,6 +459,12 @@ 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) { + 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); @@ -523,6 +528,12 @@ out: int bond_option_primary_reselect_set(struct bonding *bond, int primary_reselect) { + 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, @@ -539,6 +550,12 @@ 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) { + 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); @@ -555,6 +572,12 @@ 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) { + 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, @@ -656,3 +679,54 @@ int bond_option_packets_per_slave_set(struct bonding *bond, return 0; } + +int bond_option_lacp_rate_set(struct bonding *bond, int lacp_rate) +{ + 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; + 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) +{ + 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); + + return 0; +} diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index a0a3476fadba..9a1ea4a171c7 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -658,41 +658,23 @@ static ssize_t bonding_store_lacp(struct device *d, const char *buf, size_t count) { struct bonding *bond = to_bond(d); - int new_value, ret = count; - - if (!rtnl_trylock()) - return restart_syscall(); - - if (bond->dev->flags & IFF_UP) { - pr_err("%s: Unable to update LACP rate because interface is up.\n", - bond->dev->name); - ret = -EPERM; - goto out; - } - - if (bond->params.mode != BOND_MODE_8023AD) { - pr_err("%s: Unable to update LACP rate because bond is not in 802.3ad mode.\n", - bond->dev->name); - ret = -EPERM; - goto out; - } + int new_value, ret; new_value = bond_parse_parm(buf, bond_lacp_tbl); - - if ((new_value == 1) || (new_value == 0)) { - bond->params.lacp_fast = new_value; - bond_3ad_update_lacp_rate(bond); - pr_info("%s: Setting LACP rate to %s (%d).\n", - bond->dev->name, bond_lacp_tbl[new_value].modename, - new_value); - } else { + if (new_value < 0) { pr_err("%s: Ignoring invalid LACP rate value %.*s.\n", bond->dev->name, (int)strlen(buf) - 1, buf); - ret = -EINVAL; + return -EINVAL; } -out: - rtnl_unlock(); + if (!rtnl_trylock()) + return restart_syscall(); + + ret = bond_option_lacp_rate_set(bond, new_value); + if (!ret) + ret = count; + + rtnl_unlock(); return ret; } static DEVICE_ATTR(lacp_rate, S_IRUGO | S_IWUSR, @@ -751,29 +733,24 @@ static ssize_t bonding_store_ad_select(struct device *d, struct device_attribute *attr, const char *buf, size_t count) { - int new_value, ret = count; + int new_value, ret; struct bonding *bond = to_bond(d); - if (bond->dev->flags & IFF_UP) { - pr_err("%s: Unable to update ad_select because interface is up.\n", - bond->dev->name); - ret = -EPERM; - goto out; - } - new_value = bond_parse_parm(buf, ad_select_tbl); - - if (new_value != -1) { - bond->params.ad_select = new_value; - pr_info("%s: Setting ad_select to %s (%d).\n", - bond->dev->name, ad_select_tbl[new_value].modename, - new_value); - } else { + if (new_value < 0) { pr_err("%s: Ignoring invalid ad_select value %.*s.\n", bond->dev->name, (int)strlen(buf) - 1, buf); - ret = -EINVAL; + return -EINVAL; } -out: + + if (!rtnl_trylock()) + return restart_syscall(); + + ret = bond_option_ad_select_set(bond, new_value); + if (!ret) + ret = count; + + rtnl_unlock(); return ret; } static DEVICE_ATTR(ad_select, S_IRUGO | S_IWUSR, diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index 8e8817f3ef31..955dc4839f1d 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -425,6 +425,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev); int bond_release(struct net_device *bond_dev, struct net_device *slave_dev); int bond_xmit_hash(struct bonding *bond, struct sk_buff *skb, int count); int bond_parse_parm(const char *mode_arg, const struct bond_parm_tbl *tbl); +int bond_parm_tbl_lookup(int mode, const struct bond_parm_tbl *tbl); void bond_select_active_slave(struct bonding *bond); void bond_change_active_slave(struct bonding *bond, struct slave *new_active); void bond_create_debugfs(void); @@ -464,6 +465,8 @@ 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); diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index 8fbc7ca878b4..3e6bd3c7445d 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -349,11 +349,25 @@ enum { IFLA_BOND_MIN_LINKS, IFLA_BOND_LP_INTERVAL, IFLA_BOND_PACKETS_PER_SLAVE, + IFLA_BOND_AD_LACP_RATE, + IFLA_BOND_AD_SELECT, + IFLA_BOND_AD_INFO, __IFLA_BOND_MAX, }; #define IFLA_BOND_MAX (__IFLA_BOND_MAX - 1) +enum { + IFLA_BOND_AD_INFO_AGGREGATOR, + IFLA_BOND_AD_INFO_NUM_PORTS, + IFLA_BOND_AD_INFO_ACTOR_KEY, + IFLA_BOND_AD_INFO_PARTNER_KEY, + IFLA_BOND_AD_INFO_PARTNER_MAC, + __IFLA_BOND_AD_INFO_MAX, +}; + +#define IFLA_BOND_AD_INFO_MAX (__IFLA_BOND_AD_INFO_MAX - 1) + /* SR-IOV virtual function management section */ enum { |