diff options
Diffstat (limited to 'drivers/net/bonding')
-rw-r--r-- | drivers/net/bonding/bond_3ad.c | 21 | ||||
-rw-r--r-- | drivers/net/bonding/bond_3ad.h | 2 | ||||
-rw-r--r-- | drivers/net/bonding/bond_alb.c | 4 | ||||
-rw-r--r-- | drivers/net/bonding/bond_main.c | 98 | ||||
-rw-r--r-- | drivers/net/bonding/bond_procfs.c | 6 | ||||
-rw-r--r-- | drivers/net/bonding/bond_sysfs.c | 13 |
6 files changed, 98 insertions, 46 deletions
diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index fc58d118d84..390061d0969 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -2360,14 +2360,15 @@ int bond_3ad_set_carrier(struct bonding *bond) } /** - * bond_3ad_get_active_agg_info - get information of the active aggregator + * __bond_3ad_get_active_agg_info - get information of the active aggregator * @bond: bonding struct to work on * @ad_info: ad_info struct to fill with the bond's info * * Returns: 0 on success * < 0 on error */ -int bond_3ad_get_active_agg_info(struct bonding *bond, struct ad_info *ad_info) +int __bond_3ad_get_active_agg_info(struct bonding *bond, + struct ad_info *ad_info) { struct aggregator *aggregator = NULL; struct port *port; @@ -2391,6 +2392,18 @@ int bond_3ad_get_active_agg_info(struct bonding *bond, struct ad_info *ad_info) return -1; } +/* Wrapper used to hold bond->lock so no slave manipulation can occur */ +int bond_3ad_get_active_agg_info(struct bonding *bond, struct ad_info *ad_info) +{ + int ret; + + read_lock(&bond->lock); + ret = __bond_3ad_get_active_agg_info(bond, ad_info); + read_unlock(&bond->lock); + + return ret; +} + int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev) { struct slave *slave, *start_at; @@ -2402,8 +2415,8 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev) struct ad_info ad_info; int res = 1; - if (bond_3ad_get_active_agg_info(bond, &ad_info)) { - pr_debug("%s: Error: bond_3ad_get_active_agg_info failed\n", + if (__bond_3ad_get_active_agg_info(bond, &ad_info)) { + pr_debug("%s: Error: __bond_3ad_get_active_agg_info failed\n", dev->name); goto out; } diff --git a/drivers/net/bonding/bond_3ad.h b/drivers/net/bonding/bond_3ad.h index 0cfaa4afdec..5d91ad0cc04 100644 --- a/drivers/net/bonding/bond_3ad.h +++ b/drivers/net/bonding/bond_3ad.h @@ -273,6 +273,8 @@ void bond_3ad_adapter_speed_changed(struct slave *slave); void bond_3ad_adapter_duplex_changed(struct slave *slave); void bond_3ad_handle_link_change(struct slave *slave, char link); int bond_3ad_get_active_agg_info(struct bonding *bond, struct ad_info *ad_info); +int __bond_3ad_get_active_agg_info(struct bonding *bond, + struct ad_info *ad_info); int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev); int bond_3ad_lacpdu_recv(const struct sk_buff *skb, struct bonding *bond, struct slave *slave); diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index f5e05272302..e02cc265723 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -514,7 +514,7 @@ static void rlb_update_client(struct rlb_client_info *client_info) skb->dev = client_info->slave->dev; if (client_info->tag) { - skb = vlan_put_tag(skb, client_info->vlan_id); + skb = vlan_put_tag(skb, htons(ETH_P_8021Q), client_info->vlan_id); if (!skb) { pr_err("%s: Error: failed to insert VLAN tag\n", client_info->slave->bond->dev->name); @@ -1014,7 +1014,7 @@ static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[]) continue; } - skb = vlan_put_tag(skb, vlan->vlan_id); + skb = vlan_put_tag(skb, htons(ETH_P_8021Q), vlan->vlan_id); if (!skb) { pr_err("%s: Error: failed to insert VLAN tag\n", bond->dev->name); diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index dbbea0eec13..29b846cbfb4 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -428,14 +428,15 @@ int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, * @bond_dev: bonding net device that got called * @vid: vlan id being added */ -static int bond_vlan_rx_add_vid(struct net_device *bond_dev, uint16_t vid) +static int bond_vlan_rx_add_vid(struct net_device *bond_dev, + __be16 proto, u16 vid) { struct bonding *bond = netdev_priv(bond_dev); struct slave *slave, *stop_at; int i, res; bond_for_each_slave(bond, slave, i) { - res = vlan_vid_add(slave->dev, vid); + res = vlan_vid_add(slave->dev, proto, vid); if (res) goto unwind; } @@ -453,7 +454,7 @@ unwind: /* unwind from head to the slave that failed */ stop_at = slave; bond_for_each_slave_from_to(bond, slave, i, bond->first_slave, stop_at) - vlan_vid_del(slave->dev, vid); + vlan_vid_del(slave->dev, proto, vid); return res; } @@ -463,14 +464,15 @@ unwind: * @bond_dev: bonding net device that got called * @vid: vlan id being removed */ -static int bond_vlan_rx_kill_vid(struct net_device *bond_dev, uint16_t vid) +static int bond_vlan_rx_kill_vid(struct net_device *bond_dev, + __be16 proto, u16 vid) { struct bonding *bond = netdev_priv(bond_dev); struct slave *slave; int i, res; bond_for_each_slave(bond, slave, i) - vlan_vid_del(slave->dev, vid); + vlan_vid_del(slave->dev, proto, vid); res = bond_del_vlan(bond, vid); if (res) { @@ -488,7 +490,8 @@ static void bond_add_vlans_on_slave(struct bonding *bond, struct net_device *sla int res; list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { - res = vlan_vid_add(slave_dev, vlan->vlan_id); + res = vlan_vid_add(slave_dev, htons(ETH_P_8021Q), + vlan->vlan_id); if (res) pr_warning("%s: Failed to add vlan id %d to device %s\n", bond->dev->name, vlan->vlan_id, @@ -504,7 +507,7 @@ static void bond_del_vlans_from_slave(struct bonding *bond, list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { if (!vlan->vlan_id) continue; - vlan_vid_del(slave_dev, vlan->vlan_id); + vlan_vid_del(slave_dev, htons(ETH_P_8021Q), vlan->vlan_id); } } @@ -779,7 +782,7 @@ static void bond_resend_igmp_join_requests(struct bonding *bond) /* rejoin all groups on vlan devices */ list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { - vlan_dev = __vlan_find_dev_deep(bond_dev, + vlan_dev = __vlan_find_dev_deep(bond_dev, htons(ETH_P_8021Q), vlan->vlan_id); if (vlan_dev) __bond_resend_igmp_join_requests(vlan_dev); @@ -796,9 +799,8 @@ static void bond_resend_igmp_join_requests_delayed(struct work_struct *work) { struct bonding *bond = container_of(work, struct bonding, mcast_work.work); - rcu_read_lock(); + bond_resend_igmp_join_requests(bond); - rcu_read_unlock(); } /* @@ -1360,6 +1362,7 @@ static netdev_features_t bond_fix_features(struct net_device *dev, slave->dev->features, mask); } + features = netdev_add_tso_features(features, mask); out: read_unlock(&bond->lock); @@ -1915,14 +1918,16 @@ err_detach: bond_detach_slave(bond, new_slave); if (bond->primary_slave == new_slave) bond->primary_slave = NULL; - write_unlock_bh(&bond->lock); if (bond->curr_active_slave == new_slave) { + bond_change_active_slave(bond, NULL); + write_unlock_bh(&bond->lock); read_lock(&bond->lock); write_lock_bh(&bond->curr_slave_lock); - bond_change_active_slave(bond, NULL); bond_select_active_slave(bond); write_unlock_bh(&bond->curr_slave_lock); read_unlock(&bond->lock); + } else { + write_unlock_bh(&bond->lock); } slave_disable_netpoll(new_slave); @@ -2532,7 +2537,8 @@ static int bond_has_this_ip(struct bonding *bond, __be32 ip) list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { rcu_read_lock(); - vlan_dev = __vlan_find_dev_deep(bond->dev, vlan->vlan_id); + vlan_dev = __vlan_find_dev_deep(bond->dev, htons(ETH_P_8021Q), + vlan->vlan_id); rcu_read_unlock(); if (vlan_dev && ip == bond_confirm_addr(vlan_dev, 0, ip)) return 1; @@ -2550,8 +2556,8 @@ static void bond_arp_send(struct net_device *slave_dev, int arp_op, __be32 dest_ { struct sk_buff *skb; - pr_debug("arp %d on slave %s: dst %x src %x vid %d\n", arp_op, - slave_dev->name, dest_ip, src_ip, vlan_id); + pr_debug("arp %d on slave %s: dst %pI4 src %pI4 vid %d\n", arp_op, + slave_dev->name, &dest_ip, &src_ip, vlan_id); skb = arp_create(arp_op, ETH_P_ARP, dest_ip, slave_dev, src_ip, NULL, slave_dev->dev_addr, NULL); @@ -2561,7 +2567,7 @@ static void bond_arp_send(struct net_device *slave_dev, int arp_op, __be32 dest_ return; } if (vlan_id) { - skb = vlan_put_tag(skb, vlan_id); + skb = vlan_put_tag(skb, htons(ETH_P_8021Q), vlan_id); if (!skb) { pr_err("failed to insert VLAN tag\n"); return; @@ -2583,7 +2589,7 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave) __be32 addr; if (!targets[i]) break; - pr_debug("basa: target %x\n", targets[i]); + pr_debug("basa: target %pI4\n", &targets[i]); if (!bond_vlan_used(bond)) { pr_debug("basa: empty vlan: arp_send\n"); addr = bond_confirm_addr(bond->dev, targets[i], 0); @@ -2623,6 +2629,7 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave) list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { rcu_read_lock(); vlan_dev = __vlan_find_dev_deep(bond->dev, + htons(ETH_P_8021Q), vlan->vlan_id); rcu_read_unlock(); if (vlan_dev == rt->dst.dev) { @@ -4258,6 +4265,37 @@ void bond_set_mode_ops(struct bonding *bond, int mode) } } +static int bond_ethtool_get_settings(struct net_device *bond_dev, + struct ethtool_cmd *ecmd) +{ + struct bonding *bond = netdev_priv(bond_dev); + struct slave *slave; + int i; + unsigned long speed = 0; + + ecmd->duplex = DUPLEX_UNKNOWN; + ecmd->port = PORT_OTHER; + + /* Since SLAVE_IS_OK returns false for all inactive or down slaves, we + * do not need to check mode. Though link speed might not represent + * the true receive or transmit bandwidth (not all modes are symmetric) + * this is an accurate maximum. + */ + read_lock(&bond->lock); + bond_for_each_slave(bond, slave, i) { + if (SLAVE_IS_OK(slave)) { + if (slave->speed != SPEED_UNKNOWN) + speed += slave->speed; + if (ecmd->duplex == DUPLEX_UNKNOWN && + slave->duplex != DUPLEX_UNKNOWN) + ecmd->duplex = slave->duplex; + } + } + ethtool_cmd_speed_set(ecmd, speed ? : SPEED_UNKNOWN); + read_unlock(&bond->lock); + return 0; +} + static void bond_ethtool_get_drvinfo(struct net_device *bond_dev, struct ethtool_drvinfo *drvinfo) { @@ -4269,6 +4307,7 @@ static void bond_ethtool_get_drvinfo(struct net_device *bond_dev, static const struct ethtool_ops bond_ethtool_ops = { .get_drvinfo = bond_ethtool_get_drvinfo, + .get_settings = bond_ethtool_get_settings, .get_link = ethtool_op_get_link, }; @@ -4359,9 +4398,9 @@ static void bond_setup(struct net_device *bond_dev) */ bond_dev->hw_features = BOND_VLAN_FEATURES | - NETIF_F_HW_VLAN_TX | - NETIF_F_HW_VLAN_RX | - NETIF_F_HW_VLAN_FILTER; + NETIF_F_HW_VLAN_CTAG_TX | + NETIF_F_HW_VLAN_CTAG_RX | + NETIF_F_HW_VLAN_CTAG_FILTER; bond_dev->hw_features &= ~(NETIF_F_ALL_CSUM & ~NETIF_F_HW_CSUM); bond_dev->features |= bond_dev->hw_features; @@ -4432,7 +4471,7 @@ 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; + int arp_validate_value, fail_over_mac_value, primary_reselect_value, i; /* * Convert string parameters. @@ -4612,19 +4651,18 @@ static int bond_check_params(struct bond_params *params) arp_interval = BOND_LINK_ARP_INTERV; } - for (arp_ip_count = 0; - (arp_ip_count < BOND_MAX_ARP_TARGETS) && arp_ip_target[arp_ip_count]; - arp_ip_count++) { + for (arp_ip_count = 0, i = 0; + (arp_ip_count < BOND_MAX_ARP_TARGETS) && arp_ip_target[i]; i++) { /* not complete check, but should be good enough to catch mistakes */ - __be32 ip = in_aton(arp_ip_target[arp_ip_count]); - if (!isdigit(arp_ip_target[arp_ip_count][0]) || - ip == 0 || ip == htonl(INADDR_BROADCAST)) { + __be32 ip = in_aton(arp_ip_target[i]); + if (!isdigit(arp_ip_target[i][0]) || ip == 0 || + ip == htonl(INADDR_BROADCAST)) { pr_warning("Warning: bad arp_ip_target module parameter (%s), ARP monitoring will not be performed\n", - arp_ip_target[arp_ip_count]); + arp_ip_target[i]); arp_interval = 0; } else { - arp_target[arp_ip_count] = ip; + arp_target[arp_ip_count++] = ip; } } @@ -4658,8 +4696,6 @@ static int bond_check_params(struct bond_params *params) if (miimon) { pr_info("MII link monitoring set to %d ms\n", miimon); } else if (arp_interval) { - int i; - pr_info("ARP monitoring set to %d ms, validate %s, with %d target(s):", arp_interval, arp_validate_tbl[arp_validate_value].modename, diff --git a/drivers/net/bonding/bond_procfs.c b/drivers/net/bonding/bond_procfs.c index 3cea38d3734..4060d41f0ee 100644 --- a/drivers/net/bonding/bond_procfs.c +++ b/drivers/net/bonding/bond_procfs.c @@ -130,7 +130,7 @@ static void bond_info_show_master(struct seq_file *seq) seq_printf(seq, "Aggregator selection policy (ad_select): %s\n", ad_select_tbl[bond->params.ad_select].modename); - if (bond_3ad_get_active_agg_info(bond, &ad_info)) { + if (__bond_3ad_get_active_agg_info(bond, &ad_info)) { seq_printf(seq, "bond %s has no active aggregator\n", bond->dev->name); } else { @@ -218,15 +218,13 @@ static const struct seq_operations bond_info_seq_ops = { static int bond_info_open(struct inode *inode, struct file *file) { struct seq_file *seq; - struct proc_dir_entry *proc; int res; res = seq_open(file, &bond_info_seq_ops); if (!res) { /* recover the pointer buried in proc_dir_entry data */ seq = file->private_data; - proc = PDE(inode); - seq->private = proc->data; + seq->private = PDE_DATA(inode); } return res; diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index ea7a388f484..d7434e0a610 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -316,6 +316,9 @@ static ssize_t bonding_store_mode(struct device *d, int new_value, ret = count; struct bonding *bond = to_bond(d); + if (!rtnl_trylock()) + return restart_syscall(); + if (bond->dev->flags & IFF_UP) { pr_err("unable to update mode of %s because interface is up.\n", bond->dev->name); @@ -352,6 +355,7 @@ static ssize_t bonding_store_mode(struct device *d, bond->dev->name, bond_mode_tbl[new_value].modename, new_value); out: + rtnl_unlock(); return ret; } static DEVICE_ATTR(mode, S_IRUGO | S_IWUSR, @@ -1315,7 +1319,6 @@ static ssize_t bonding_show_mii_status(struct device *d, } static DEVICE_ATTR(mii_status, S_IRUGO, bonding_show_mii_status, NULL); - /* * Show current 802.3ad aggregator ID. */ @@ -1329,7 +1332,7 @@ static ssize_t bonding_show_ad_aggregator(struct device *d, if (bond->params.mode == BOND_MODE_8023AD) { struct ad_info ad_info; count = sprintf(buf, "%d\n", - (bond_3ad_get_active_agg_info(bond, &ad_info)) + bond_3ad_get_active_agg_info(bond, &ad_info) ? 0 : ad_info.aggregator_id); } @@ -1351,7 +1354,7 @@ static ssize_t bonding_show_ad_num_ports(struct device *d, if (bond->params.mode == BOND_MODE_8023AD) { struct ad_info ad_info; count = sprintf(buf, "%d\n", - (bond_3ad_get_active_agg_info(bond, &ad_info)) + bond_3ad_get_active_agg_info(bond, &ad_info) ? 0 : ad_info.ports); } @@ -1373,7 +1376,7 @@ static ssize_t bonding_show_ad_actor_key(struct device *d, if (bond->params.mode == BOND_MODE_8023AD) { struct ad_info ad_info; count = sprintf(buf, "%d\n", - (bond_3ad_get_active_agg_info(bond, &ad_info)) + bond_3ad_get_active_agg_info(bond, &ad_info) ? 0 : ad_info.actor_key); } @@ -1395,7 +1398,7 @@ static ssize_t bonding_show_ad_partner_key(struct device *d, if (bond->params.mode == BOND_MODE_8023AD) { struct ad_info ad_info; count = sprintf(buf, "%d\n", - (bond_3ad_get_active_agg_info(bond, &ad_info)) + bond_3ad_get_active_agg_info(bond, &ad_info) ? 0 : ad_info.partner_key); } |