diff options
Diffstat (limited to 'drivers/net/bonding/bond_main.c')
-rw-r--r-- | drivers/net/bonding/bond_main.c | 644 |
1 files changed, 232 insertions, 412 deletions
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index e48cb339c0c6..4264a7631cba 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -77,6 +77,7 @@ #include <net/net_namespace.h> #include <net/netns/generic.h> #include <net/pkt_sched.h> +#include <linux/rculist.h> #include "bonding.h" #include "bond_3ad.h" #include "bond_alb.h" @@ -106,7 +107,7 @@ static char *arp_ip_target[BOND_MAX_ARP_TARGETS]; static char *arp_validate; static char *arp_all_targets; static char *fail_over_mac; -static int all_slaves_active = 0; +static int all_slaves_active; static struct bond_params bonding_defaults; static int resend_igmp = BOND_DEFAULT_RESEND_IGMP; @@ -273,7 +274,7 @@ const char *bond_mode_name(int mode) [BOND_MODE_ALB] = "adaptive load balancing", }; - if (mode < 0 || mode > BOND_MODE_ALB) + if (mode < BOND_MODE_ROUNDROBIN || mode > BOND_MODE_ALB) return "unknown"; return names[mode]; @@ -441,10 +442,10 @@ 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; + struct slave *slave; + int res; - bond_for_each_slave(bond, slave, i) { + bond_for_each_slave(bond, slave) { res = vlan_vid_add(slave->dev, proto, vid); if (res) goto unwind; @@ -454,15 +455,14 @@ static int bond_vlan_rx_add_vid(struct net_device *bond_dev, if (res) { pr_err("%s: Error: Failed to add vlan id %d\n", bond_dev->name, vid); - return res; + goto unwind; } return 0; 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) + /* unwind from the slave that failed */ + bond_for_each_slave_continue_reverse(bond, slave) vlan_vid_del(slave->dev, proto, vid); return res; @@ -478,9 +478,9 @@ static int bond_vlan_rx_kill_vid(struct net_device *bond_dev, { struct bonding *bond = netdev_priv(bond_dev); struct slave *slave; - int i, res; + int res; - bond_for_each_slave(bond, slave, i) + bond_for_each_slave(bond, slave) vlan_vid_del(slave->dev, proto, vid); res = bond_del_vlan(bond, vid); @@ -493,33 +493,6 @@ static int bond_vlan_rx_kill_vid(struct net_device *bond_dev, return 0; } -static void bond_add_vlans_on_slave(struct bonding *bond, struct net_device *slave_dev) -{ - struct vlan_entry *vlan; - int res; - - list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { - 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, - slave_dev->name); - } -} - -static void bond_del_vlans_from_slave(struct bonding *bond, - struct net_device *slave_dev) -{ - struct vlan_entry *vlan; - - list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { - if (!vlan->vlan_id) - continue; - vlan_vid_del(slave_dev, htons(ETH_P_8021Q), vlan->vlan_id); - } -} - /*------------------------------- Link status -------------------------------*/ /* @@ -532,15 +505,14 @@ static void bond_del_vlans_from_slave(struct bonding *bond, static int bond_set_carrier(struct bonding *bond) { struct slave *slave; - int i; - if (bond->slave_cnt == 0) + if (list_empty(&bond->slave_list)) goto down; if (bond->params.mode == BOND_MODE_8023AD) return bond_3ad_set_carrier(bond); - bond_for_each_slave(bond, slave, i) { + bond_for_each_slave(bond, slave) { if (slave->link == BOND_LINK_UP) { if (!netif_carrier_ok(bond->dev)) { netif_carrier_on(bond->dev); @@ -681,8 +653,8 @@ static int bond_set_promiscuity(struct bonding *bond, int inc) } } else { struct slave *slave; - int i; - bond_for_each_slave(bond, slave, i) { + + bond_for_each_slave(bond, slave) { err = dev_set_promiscuity(slave->dev, inc); if (err) return err; @@ -705,8 +677,8 @@ static int bond_set_allmulti(struct bonding *bond, int inc) } } else { struct slave *slave; - int i; - bond_for_each_slave(bond, slave, i) { + + bond_for_each_slave(bond, slave) { err = dev_set_allmulti(slave->dev, inc); if (err) return err; @@ -715,15 +687,6 @@ static int bond_set_allmulti(struct bonding *bond, int inc) return err; } -static void __bond_resend_igmp_join_requests(struct net_device *dev) -{ - struct in_device *in_dev; - - in_dev = __in_dev_get_rcu(dev); - if (in_dev) - ip_mc_rejoin_groups(in_dev); -} - /* * Retrieve the list of registered multicast addresses for the bonding * device and retransmit an IGMP JOIN request to the current active @@ -731,33 +694,12 @@ static void __bond_resend_igmp_join_requests(struct net_device *dev) */ static void bond_resend_igmp_join_requests(struct bonding *bond) { - struct net_device *bond_dev, *vlan_dev, *upper_dev; - struct vlan_entry *vlan; - - read_lock(&bond->lock); - rcu_read_lock(); - - bond_dev = bond->dev; - - /* rejoin all groups on bond device */ - __bond_resend_igmp_join_requests(bond_dev); - - /* - * if bond is enslaved to a bridge, - * then rejoin all groups on its master - */ - upper_dev = netdev_master_upper_dev_get_rcu(bond_dev); - if (upper_dev && upper_dev->priv_flags & IFF_EBRIDGE) - __bond_resend_igmp_join_requests(upper_dev); - - /* rejoin all groups on vlan devices */ - list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { - 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); + if (!rtnl_trylock()) { + queue_delayed_work(bond->wq, &bond->mcast_work, 1); + return; } - rcu_read_unlock(); + call_netdevice_notifiers(NETDEV_RESEND_IGMP, bond->dev); + rtnl_unlock(); /* We use curr_slave_lock to protect against concurrent access to * igmp_retrans from multiple running instances of this function and @@ -769,7 +711,6 @@ static void bond_resend_igmp_join_requests(struct bonding *bond) queue_delayed_work(bond->wq, &bond->mcast_work, HZ/5); } write_unlock_bh(&bond->curr_slave_lock); - read_unlock(&bond->lock); } static void bond_resend_igmp_join_requests_delayed(struct work_struct *work) @@ -808,6 +749,8 @@ static void bond_hw_addr_flush(struct net_device *bond_dev, static void bond_hw_addr_swap(struct bonding *bond, struct slave *new_active, struct slave *old_active) { + ASSERT_RTNL(); + if (old_active) { if (bond->dev->flags & IFF_PROMISC) dev_set_promiscuity(old_active->dev, -1); @@ -966,9 +909,8 @@ static struct slave *bond_find_best_slave(struct bonding *bond) new_active = bond->curr_active_slave; if (!new_active) { /* there were no active slaves left */ - if (bond->slave_cnt > 0) /* found one slave */ - new_active = bond->first_slave; - else + new_active = bond_first_slave(bond); + if (!new_active) return NULL; /* still no slave, return NULL */ } @@ -1071,7 +1013,7 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active) if (new_active) bond_set_slave_active_flags(new_active); } else { - bond->curr_active_slave = new_active; + rcu_assign_pointer(bond->curr_active_slave, new_active); } if (bond->params.mode == BOND_MODE_ACTIVEBACKUP) { @@ -1115,7 +1057,7 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active) ((USES_PRIMARY(bond->params.mode) && new_active) || bond->params.mode == BOND_MODE_ROUNDROBIN)) { bond->igmp_retrans = bond->params.resend_igmp; - queue_delayed_work(bond->wq, &bond->mcast_work, 0); + queue_delayed_work(bond->wq, &bond->mcast_work, 1); } } @@ -1161,17 +1103,7 @@ void bond_select_active_slave(struct bonding *bond) */ static void bond_attach_slave(struct bonding *bond, struct slave *new_slave) { - if (bond->first_slave == NULL) { /* attaching the first slave */ - new_slave->next = new_slave; - new_slave->prev = new_slave; - bond->first_slave = new_slave; - } else { - new_slave->next = bond->first_slave; - new_slave->prev = bond->first_slave->prev; - new_slave->next->prev = new_slave; - new_slave->prev->next = new_slave; - } - + list_add_tail_rcu(&new_slave->list, &bond->slave_list); bond->slave_cnt++; } @@ -1187,22 +1119,7 @@ static void bond_attach_slave(struct bonding *bond, struct slave *new_slave) */ static void bond_detach_slave(struct bonding *bond, struct slave *slave) { - if (slave->next) - slave->next->prev = slave->prev; - - if (slave->prev) - slave->prev->next = slave->next; - - if (bond->first_slave == slave) { /* slave is the first slave */ - if (bond->slave_cnt > 1) { /* there are more slave */ - bond->first_slave = slave->next; - } else { - bond->first_slave = NULL; /* slave was the last one */ - } - } - - slave->next = NULL; - slave->prev = NULL; + list_del_rcu(&slave->list); bond->slave_cnt--; } @@ -1249,47 +1166,31 @@ static void bond_poll_controller(struct net_device *bond_dev) { } -static void __bond_netpoll_cleanup(struct bonding *bond) +static void bond_netpoll_cleanup(struct net_device *bond_dev) { + struct bonding *bond = netdev_priv(bond_dev); struct slave *slave; - int i; - bond_for_each_slave(bond, slave, i) + bond_for_each_slave(bond, slave) if (IS_UP(slave->dev)) slave_disable_netpoll(slave); } -static void bond_netpoll_cleanup(struct net_device *bond_dev) -{ - struct bonding *bond = netdev_priv(bond_dev); - - read_lock(&bond->lock); - __bond_netpoll_cleanup(bond); - read_unlock(&bond->lock); -} static int bond_netpoll_setup(struct net_device *dev, struct netpoll_info *ni, gfp_t gfp) { struct bonding *bond = netdev_priv(dev); struct slave *slave; - int i, err = 0; + int err = 0; - read_lock(&bond->lock); - bond_for_each_slave(bond, slave, i) { + bond_for_each_slave(bond, slave) { err = slave_enable_netpoll(slave); if (err) { - __bond_netpoll_cleanup(bond); + bond_netpoll_cleanup(dev); break; } } - read_unlock(&bond->lock); return err; } - -static struct netpoll_info *bond_netpoll_info(struct bonding *bond) -{ - return bond->dev->npinfo; -} - #else static inline int slave_enable_netpoll(struct slave *slave) { @@ -1311,11 +1212,10 @@ static netdev_features_t bond_fix_features(struct net_device *dev, struct slave *slave; struct bonding *bond = netdev_priv(dev); netdev_features_t mask; - int i; read_lock(&bond->lock); - if (!bond->first_slave) { + if (list_empty(&bond->slave_list)) { /* Disable adding VLANs to empty bond. But why? --mq */ features |= NETIF_F_VLAN_CHALLENGED; goto out; @@ -1325,7 +1225,7 @@ static netdev_features_t bond_fix_features(struct net_device *dev, features &= ~NETIF_F_ONE_FOR_ALL; features |= NETIF_F_ALL_FOR_ALL; - bond_for_each_slave(bond, slave, i) { + bond_for_each_slave(bond, slave) { features = netdev_increment_features(features, slave->dev->features, mask); @@ -1349,15 +1249,14 @@ static void bond_compute_features(struct bonding *bond) unsigned short max_hard_header_len = ETH_HLEN; unsigned int gso_max_size = GSO_MAX_SIZE; u16 gso_max_segs = GSO_MAX_SEGS; - int i; unsigned int flags, dst_release_flag = IFF_XMIT_DST_RELEASE; read_lock(&bond->lock); - if (!bond->first_slave) + if (list_empty(&bond->slave_list)) goto done; - bond_for_each_slave(bond, slave, i) { + bond_for_each_slave(bond, slave) { vlan_features = netdev_increment_features(vlan_features, slave->dev->vlan_features, BOND_VLAN_FEATURES); @@ -1545,7 +1444,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) * bond ether type mutual exclusion - don't allow slaves of dissimilar * ether type (eg ARPHRD_ETHER and ARPHRD_INFINIBAND) share the same bond */ - if (bond->slave_cnt == 0) { + if (list_empty(&bond->slave_list)) { if (bond_dev->type != slave_dev->type) { pr_debug("%s: change device type from %d to %d\n", bond_dev->name, @@ -1584,7 +1483,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) } if (slave_ops->ndo_set_mac_address == NULL) { - if (bond->slave_cnt == 0) { + if (list_empty(&bond->slave_list)) { pr_warning("%s: Warning: The first slave device specified does not support setting the MAC address. Setting fail_over_mac to active.", bond_dev->name); bond->params.fail_over_mac = BOND_FOM_ACTIVE; @@ -1600,7 +1499,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) /* If this is the first slave, then we need to set the master's hardware * address to be the same as the slave's. */ - if (!bond->slave_cnt && bond->dev->addr_assign_type == NET_ADDR_RANDOM) + if (list_empty(&bond->slave_list) && + bond->dev->addr_assign_type == NET_ADDR_RANDOM) bond_set_dev_addr(bond->dev, slave_dev); new_slave = kzalloc(sizeof(struct slave), GFP_KERNEL); @@ -1608,7 +1508,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) res = -ENOMEM; goto err_undo_flags; } - + INIT_LIST_HEAD(&new_slave->list); /* * Set the new_slave's queue_id to be zero. Queue ID mapping * is set via sysfs or module option if desired. @@ -1703,7 +1603,11 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) dev_mc_add(slave_dev, lacpdu_multicast); } - bond_add_vlans_on_slave(bond, slave_dev); + if (vlan_vids_add_by_dev(slave_dev, bond_dev)) { + pr_err("%s: Error: Couldn't add bond vlan ids to %s\n", + bond_dev->name, slave_dev->name); + goto err_close; + } write_lock_bh(&bond->lock); @@ -1794,15 +1698,18 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) */ bond_set_slave_inactive_flags(new_slave); /* if this is the first slave */ - if (bond->slave_cnt == 1) { + if (bond_first_slave(bond) == new_slave) { SLAVE_AD_INFO(new_slave).id = 1; /* Initialize AD with the number of times that the AD timer is called in 1 second * can be called only after the mac address of the bond is set */ bond_3ad_initialize(bond, 1000/AD_TIMER_INTERVAL); } else { + struct slave *prev_slave; + + prev_slave = bond_prev_slave(bond, new_slave); SLAVE_AD_INFO(new_slave).id = - SLAVE_AD_INFO(new_slave->prev).id + 1; + SLAVE_AD_INFO(prev_slave).id + 1; } bond_3ad_bind_slave(new_slave); @@ -1824,7 +1731,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) * so we can change it without calling change_active_interface() */ if (!bond->curr_active_slave && new_slave->link == BOND_LINK_UP) - bond->curr_active_slave = new_slave; + rcu_assign_pointer(bond->curr_active_slave, new_slave); break; } /* switch(bond_mode) */ @@ -1834,7 +1741,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) bond_set_carrier(bond); #ifdef CONFIG_NET_POLL_CONTROLLER - slave_dev->npinfo = bond_netpoll_info(bond); + slave_dev->npinfo = bond->dev->npinfo; if (slave_dev->npinfo) { if (slave_enable_netpoll(new_slave)) { read_unlock(&bond->lock); @@ -1876,7 +1783,7 @@ err_detach: if (!USES_PRIMARY(bond->params.mode)) bond_hw_addr_flush(bond_dev, slave_dev); - bond_del_vlans_from_slave(bond, slave_dev); + vlan_vids_del_by_dev(slave_dev, bond_dev); write_lock_bh(&bond->lock); bond_detach_slave(bond, new_slave); if (bond->primary_slave == new_slave) @@ -1921,7 +1828,7 @@ err_free: err_undo_flags: bond_compute_features(bond); /* Enslave of first slave has failed and we need to fix master's mac */ - if (bond->slave_cnt == 0 && + if (list_empty(&bond->slave_list) && ether_addr_equal(bond_dev->dev_addr, slave_dev->dev_addr)) eth_hw_addr_random(bond_dev); @@ -1977,15 +1884,6 @@ static int __bond_release_one(struct net_device *bond_dev, netdev_rx_handler_unregister(slave_dev); write_lock_bh(&bond->lock); - if (!all && !bond->params.fail_over_mac) { - if (ether_addr_equal(bond_dev->dev_addr, slave->perm_hwaddr) && - bond->slave_cnt > 1) - pr_warning("%s: Warning: the permanent HWaddr of %s - %pM - is still in use by %s. Set the HWaddr of %s to a different address to avoid conflicts.\n", - bond_dev->name, slave_dev->name, - slave->perm_hwaddr, - bond_dev->name, slave_dev->name); - } - /* Inform AD package of unbinding of slave. */ if (bond->params.mode == BOND_MODE_8023AD) { /* must be called before the slave is @@ -2006,6 +1904,15 @@ static int __bond_release_one(struct net_device *bond_dev, /* release the slave from its bond */ bond_detach_slave(bond, slave); + if (!all && !bond->params.fail_over_mac) { + if (ether_addr_equal(bond_dev->dev_addr, slave->perm_hwaddr) && + !list_empty(&bond->slave_list)) + pr_warn("%s: Warning: the permanent HWaddr of %s - %pM - is still in use by %s. Set the HWaddr of %s to a different address to avoid conflicts.\n", + bond_dev->name, slave_dev->name, + slave->perm_hwaddr, + bond_dev->name, slave_dev->name); + } + if (bond->primary_slave == slave) bond->primary_slave = NULL; @@ -2024,7 +1931,7 @@ static int __bond_release_one(struct net_device *bond_dev, } if (all) { - bond->curr_active_slave = NULL; + rcu_assign_pointer(bond->curr_active_slave, NULL); } else if (oldcurrent == slave) { /* * Note that we hold RTNL over this sequence, so there @@ -2042,7 +1949,7 @@ static int __bond_release_one(struct net_device *bond_dev, write_lock_bh(&bond->lock); } - if (bond->slave_cnt == 0) { + if (list_empty(&bond->slave_list)) { bond_set_carrier(bond); eth_hw_addr_random(bond_dev); @@ -2056,8 +1963,9 @@ static int __bond_release_one(struct net_device *bond_dev, write_unlock_bh(&bond->lock); unblock_netpoll_tx(); + synchronize_rcu(); - if (bond->slave_cnt == 0) { + if (list_empty(&bond->slave_list)) { call_netdevice_notifiers(NETDEV_CHANGEADDR, bond->dev); call_netdevice_notifiers(NETDEV_RELEASE, bond->dev); } @@ -2071,7 +1979,7 @@ static int __bond_release_one(struct net_device *bond_dev, /* must do this from outside any spinlocks */ bond_destroy_slave_symlinks(bond_dev, slave_dev); - bond_del_vlans_from_slave(bond, slave_dev); + vlan_vids_del_by_dev(slave_dev, bond_dev); /* If the mode USES_PRIMARY, then this cases was handled above by * bond_change_active_slave(..., NULL) @@ -2128,7 +2036,7 @@ static int bond_release_and_destroy(struct net_device *bond_dev, int ret; ret = bond_release(bond_dev, slave_dev); - if ((ret == 0) && (bond->slave_cnt == 0)) { + if (ret == 0 && list_empty(&bond->slave_list)) { bond_dev->priv_flags |= IFF_DISABLE_NETPOLL; pr_info("%s: destroying bond %s.\n", bond_dev->name, bond_dev->name); @@ -2165,23 +2073,19 @@ static int bond_ioctl_change_active(struct net_device *bond_dev, struct net_devi read_lock(&bond->lock); - read_lock(&bond->curr_slave_lock); old_active = bond->curr_active_slave; - read_unlock(&bond->curr_slave_lock); - new_active = bond_get_slave_by_dev(bond, slave_dev); - /* * Changing to the current active: do nothing; return success. */ - if (new_active && (new_active == old_active)) { + if (new_active && new_active == old_active) { read_unlock(&bond->lock); return 0; } - if ((new_active) && - (old_active) && - (new_active->link == BOND_LINK_UP) && + if (new_active && + old_active && + new_active->link == BOND_LINK_UP && IS_UP(new_active->dev)) { block_netpoll_tx(); write_lock_bh(&bond->curr_slave_lock); @@ -2213,13 +2117,12 @@ static int bond_info_query(struct net_device *bond_dev, struct ifbond *info) static int bond_slave_info_query(struct net_device *bond_dev, struct ifslave *info) { struct bonding *bond = netdev_priv(bond_dev); + int i = 0, res = -ENODEV; struct slave *slave; - int i, res = -ENODEV; read_lock(&bond->lock); - - bond_for_each_slave(bond, slave, i) { - if (i == (int)info->slave_id) { + bond_for_each_slave(bond, slave) { + if (i++ == (int)info->slave_id) { res = 0; strcpy(info->slave_name, slave->dev->name); info->link = slave->link; @@ -2228,7 +2131,6 @@ static int bond_slave_info_query(struct net_device *bond_dev, struct ifslave *in break; } } - read_unlock(&bond->lock); return res; @@ -2239,13 +2141,13 @@ static int bond_slave_info_query(struct net_device *bond_dev, struct ifslave *in static int bond_miimon_inspect(struct bonding *bond) { + int link_state, commit = 0; struct slave *slave; - int i, link_state, commit = 0; bool ignore_updelay; ignore_updelay = !bond->curr_active_slave ? true : false; - bond_for_each_slave(bond, slave, i) { + bond_for_each_slave(bond, slave) { slave->new_link = BOND_LINK_NOCHANGE; link_state = bond_check_dev_link(bond, slave->dev, 0); @@ -2340,9 +2242,8 @@ static int bond_miimon_inspect(struct bonding *bond) static void bond_miimon_commit(struct bonding *bond) { struct slave *slave; - int i; - bond_for_each_slave(bond, slave, i) { + bond_for_each_slave(bond, slave) { switch (slave->new_link) { case BOND_LINK_NOCHANGE: continue; @@ -2447,7 +2348,7 @@ void bond_mii_monitor(struct work_struct *work) delay = msecs_to_jiffies(bond->params.miimon); - if (bond->slave_cnt == 0) + if (list_empty(&bond->slave_list)) goto re_arm; should_notify_peers = bond_should_notify_peers(bond); @@ -2713,6 +2614,20 @@ out_unlock: return RX_HANDLER_ANOTHER; } +/* function to verify if we're in the arp_interval timeslice, returns true if + * (last_act - arp_interval) <= jiffies <= (last_act + mod * arp_interval + + * arp_interval/2) . the arp_interval/2 is needed for really fast networks. + */ +static bool bond_time_in_interval(struct bonding *bond, unsigned long last_act, + int mod) +{ + int delta_in_ticks = msecs_to_jiffies(bond->params.arp_interval); + + return time_in_range(jiffies, + last_act - delta_in_ticks, + last_act + mod * delta_in_ticks + delta_in_ticks/2); +} + /* * this function is called regularly to monitor each slave's link * ensuring that traffic is being sent and received when arp monitoring @@ -2726,21 +2641,13 @@ void bond_loadbalance_arp_mon(struct work_struct *work) arp_work.work); struct slave *slave, *oldcurrent; int do_failover = 0; - int delta_in_ticks, extra_ticks; - int i; read_lock(&bond->lock); - delta_in_ticks = msecs_to_jiffies(bond->params.arp_interval); - extra_ticks = delta_in_ticks / 2; - - if (bond->slave_cnt == 0) + if (list_empty(&bond->slave_list)) goto re_arm; - read_lock(&bond->curr_slave_lock); oldcurrent = bond->curr_active_slave; - read_unlock(&bond->curr_slave_lock); - /* see if any of the previous devices are up now (i.e. they have * xmt and rcv traffic). the curr_active_slave does not come into * the picture unless it is null. also, slave->jiffies is not needed @@ -2749,16 +2656,12 @@ void bond_loadbalance_arp_mon(struct work_struct *work) * TODO: what about up/down delay in arp mode? it wasn't here before * so it can wait */ - bond_for_each_slave(bond, slave, i) { + bond_for_each_slave(bond, slave) { unsigned long trans_start = dev_trans_start(slave->dev); if (slave->link != BOND_LINK_UP) { - if (time_in_range(jiffies, - trans_start - delta_in_ticks, - trans_start + delta_in_ticks + extra_ticks) && - time_in_range(jiffies, - slave->dev->last_rx - delta_in_ticks, - slave->dev->last_rx + delta_in_ticks + extra_ticks)) { + if (bond_time_in_interval(bond, trans_start, 1) && + bond_time_in_interval(bond, slave->dev->last_rx, 1)) { slave->link = BOND_LINK_UP; bond_set_active_slave(slave); @@ -2786,12 +2689,8 @@ void bond_loadbalance_arp_mon(struct work_struct *work) * when the source ip is 0, so don't take the link down * if we don't know our ip yet */ - if (!time_in_range(jiffies, - trans_start - delta_in_ticks, - trans_start + 2 * delta_in_ticks + extra_ticks) || - !time_in_range(jiffies, - slave->dev->last_rx - delta_in_ticks, - slave->dev->last_rx + 2 * delta_in_ticks + extra_ticks)) { + if (!bond_time_in_interval(bond, trans_start, 2) || + !bond_time_in_interval(bond, slave->dev->last_rx, 2)) { slave->link = BOND_LINK_DOWN; bond_set_backup_slave(slave); @@ -2831,7 +2730,8 @@ void bond_loadbalance_arp_mon(struct work_struct *work) re_arm: if (bond->params.arp_interval) - queue_delayed_work(bond->wq, &bond->arp_work, delta_in_ticks); + queue_delayed_work(bond->wq, &bond->arp_work, + msecs_to_jiffies(bond->params.arp_interval)); read_unlock(&bond->lock); } @@ -2844,32 +2744,21 @@ re_arm: * * Called with bond->lock held for read. */ -static int bond_ab_arp_inspect(struct bonding *bond, int delta_in_ticks) +static int bond_ab_arp_inspect(struct bonding *bond) { + unsigned long trans_start, last_rx; struct slave *slave; - int i, commit = 0; - unsigned long trans_start; - int extra_ticks; + int commit = 0; - /* All the time comparisons below need some extra time. Otherwise, on - * fast networks the ARP probe/reply may arrive within the same jiffy - * as it was sent. Then, the next time the ARP monitor is run, one - * arp_interval will already have passed in the comparisons. - */ - extra_ticks = delta_in_ticks / 2; - - bond_for_each_slave(bond, slave, i) { + bond_for_each_slave(bond, slave) { slave->new_link = BOND_LINK_NOCHANGE; + last_rx = slave_last_rx(bond, slave); if (slave->link != BOND_LINK_UP) { - if (time_in_range(jiffies, - slave_last_rx(bond, slave) - delta_in_ticks, - slave_last_rx(bond, slave) + delta_in_ticks + extra_ticks)) { - + if (bond_time_in_interval(bond, last_rx, 1)) { slave->new_link = BOND_LINK_UP; commit++; } - continue; } @@ -2878,9 +2767,7 @@ static int bond_ab_arp_inspect(struct bonding *bond, int delta_in_ticks) * active. This avoids bouncing, as the last receive * times need a full ARP monitor cycle to be updated. */ - if (time_in_range(jiffies, - slave->jiffies - delta_in_ticks, - slave->jiffies + 2 * delta_in_ticks + extra_ticks)) + if (bond_time_in_interval(bond, slave->jiffies, 2)) continue; /* @@ -2898,10 +2785,7 @@ static int bond_ab_arp_inspect(struct bonding *bond, int delta_in_ticks) */ if (!bond_is_active_slave(slave) && !bond->current_arp_slave && - !time_in_range(jiffies, - slave_last_rx(bond, slave) - delta_in_ticks, - slave_last_rx(bond, slave) + 3 * delta_in_ticks + extra_ticks)) { - + !bond_time_in_interval(bond, last_rx, 3)) { slave->new_link = BOND_LINK_DOWN; commit++; } @@ -2914,13 +2798,8 @@ static int bond_ab_arp_inspect(struct bonding *bond, int delta_in_ticks) */ trans_start = dev_trans_start(slave->dev); if (bond_is_active_slave(slave) && - (!time_in_range(jiffies, - trans_start - delta_in_ticks, - trans_start + 2 * delta_in_ticks + extra_ticks) || - !time_in_range(jiffies, - slave_last_rx(bond, slave) - delta_in_ticks, - slave_last_rx(bond, slave) + 2 * delta_in_ticks + extra_ticks))) { - + (!bond_time_in_interval(bond, trans_start, 2) || + !bond_time_in_interval(bond, last_rx, 2))) { slave->new_link = BOND_LINK_DOWN; commit++; } @@ -2935,24 +2814,21 @@ static int bond_ab_arp_inspect(struct bonding *bond, int delta_in_ticks) * * Called with RTNL and bond->lock for read. */ -static void bond_ab_arp_commit(struct bonding *bond, int delta_in_ticks) +static void bond_ab_arp_commit(struct bonding *bond) { - struct slave *slave; - int i; unsigned long trans_start; + struct slave *slave; - bond_for_each_slave(bond, slave, i) { + bond_for_each_slave(bond, slave) { switch (slave->new_link) { case BOND_LINK_NOCHANGE: continue; case BOND_LINK_UP: trans_start = dev_trans_start(slave->dev); - if ((!bond->curr_active_slave && - time_in_range(jiffies, - trans_start - delta_in_ticks, - trans_start + delta_in_ticks + delta_in_ticks / 2)) || - bond->curr_active_slave != slave) { + if (bond->curr_active_slave != slave || + (!bond->curr_active_slave && + bond_time_in_interval(bond, trans_start, 1))) { slave->link = BOND_LINK_UP; if (bond->current_arp_slave) { bond_set_slave_inactive_flags( @@ -3014,7 +2890,7 @@ do_failover: */ static void bond_ab_arp_probe(struct bonding *bond) { - struct slave *slave; + struct slave *slave, *next_slave; int i; read_lock(&bond->curr_slave_lock); @@ -3038,7 +2914,7 @@ static void bond_ab_arp_probe(struct bonding *bond) */ if (!bond->current_arp_slave) { - bond->current_arp_slave = bond->first_slave; + bond->current_arp_slave = bond_first_slave(bond); if (!bond->current_arp_slave) return; } @@ -3046,7 +2922,8 @@ static void bond_ab_arp_probe(struct bonding *bond) bond_set_slave_inactive_flags(bond->current_arp_slave); /* search for next candidate */ - bond_for_each_slave_from(bond, slave, i, bond->current_arp_slave->next) { + next_slave = bond_next_slave(bond, bond->current_arp_slave); + bond_for_each_slave_from(bond, slave, i, next_slave) { if (IS_UP(slave->dev)) { slave->link = BOND_LINK_BACK; bond_set_slave_active_flags(slave); @@ -3087,12 +2964,12 @@ void bond_activebackup_arp_mon(struct work_struct *work) delta_in_ticks = msecs_to_jiffies(bond->params.arp_interval); - if (bond->slave_cnt == 0) + if (list_empty(&bond->slave_list)) goto re_arm; should_notify_peers = bond_should_notify_peers(bond); - if (bond_ab_arp_inspect(bond, delta_in_ticks)) { + if (bond_ab_arp_inspect(bond)) { read_unlock(&bond->lock); /* Race avoidance with bond_close flush of workqueue */ @@ -3105,7 +2982,7 @@ void bond_activebackup_arp_mon(struct work_struct *work) read_lock(&bond->lock); - bond_ab_arp_commit(bond, delta_in_ticks); + bond_ab_arp_commit(bond); read_unlock(&bond->lock); rtnl_unlock(); @@ -3234,6 +3111,10 @@ static int bond_slave_netdev_event(unsigned long event, case NETDEV_FEAT_CHANGE: bond_compute_features(bond); break; + case NETDEV_RESEND_IGMP: + /* Propagate to master device */ + call_netdevice_notifiers(event, slave->bond->dev); + break; default: break; } @@ -3403,13 +3284,12 @@ static int bond_open(struct net_device *bond_dev) { struct bonding *bond = netdev_priv(bond_dev); struct slave *slave; - int i; /* reset slave->backup and slave->inactive */ read_lock(&bond->lock); - if (bond->slave_cnt > 0) { + if (!list_empty(&bond->slave_list)) { read_lock(&bond->curr_slave_lock); - bond_for_each_slave(bond, slave, i) { + bond_for_each_slave(bond, slave) { if ((bond->params.mode == BOND_MODE_ACTIVEBACKUP) && (slave != bond->curr_active_slave)) { bond_set_slave_inactive_flags(slave); @@ -3477,13 +3357,11 @@ static struct rtnl_link_stats64 *bond_get_stats(struct net_device *bond_dev, struct bonding *bond = netdev_priv(bond_dev); struct rtnl_link_stats64 temp; struct slave *slave; - int i; memset(stats, 0, sizeof(*stats)); read_lock_bh(&bond->lock); - - bond_for_each_slave(bond, slave, i) { + bond_for_each_slave(bond, slave) { const struct rtnl_link_stats64 *sstats = dev_get_stats(slave->dev, &temp); @@ -3513,7 +3391,6 @@ static struct rtnl_link_stats64 *bond_get_stats(struct net_device *bond_dev, stats->tx_heartbeat_errors += sstats->tx_heartbeat_errors; stats->tx_window_errors += sstats->tx_window_errors; } - read_unlock_bh(&bond->lock); return stats; @@ -3652,41 +3529,35 @@ static void bond_set_rx_mode(struct net_device *bond_dev) { struct bonding *bond = netdev_priv(bond_dev); struct slave *slave; - int i; - read_lock(&bond->lock); + ASSERT_RTNL(); if (USES_PRIMARY(bond->params.mode)) { - read_lock(&bond->curr_slave_lock); - slave = bond->curr_active_slave; + slave = rtnl_dereference(bond->curr_active_slave); if (slave) { dev_uc_sync(slave->dev, bond_dev); dev_mc_sync(slave->dev, bond_dev); } - read_unlock(&bond->curr_slave_lock); } else { - bond_for_each_slave(bond, slave, i) { + bond_for_each_slave(bond, slave) { dev_uc_sync_multiple(slave->dev, bond_dev); dev_mc_sync_multiple(slave->dev, bond_dev); } } - - read_unlock(&bond->lock); } static int bond_neigh_init(struct neighbour *n) { struct bonding *bond = netdev_priv(n->dev); - struct slave *slave = bond->first_slave; const struct net_device_ops *slave_ops; struct neigh_parms parms; + struct slave *slave; int ret; + slave = bond_first_slave(bond); if (!slave) return 0; - slave_ops = slave->dev->netdev_ops; - if (!slave_ops->ndo_neigh_setup) return 0; @@ -3735,9 +3606,8 @@ static int bond_neigh_setup(struct net_device *dev, static int bond_change_mtu(struct net_device *bond_dev, int new_mtu) { struct bonding *bond = netdev_priv(bond_dev); - struct slave *slave, *stop_at; + struct slave *slave; int res = 0; - int i; pr_debug("bond=%p, name=%s, new_mtu=%d\n", bond, (bond_dev ? bond_dev->name : "None"), new_mtu); @@ -3757,10 +3627,10 @@ static int bond_change_mtu(struct net_device *bond_dev, int new_mtu) * call to the base driver. */ - bond_for_each_slave(bond, slave, i) { + bond_for_each_slave(bond, slave) { pr_debug("s %p s->p %p c_m %p\n", slave, - slave->prev, + bond_prev_slave(bond, slave), slave->dev->netdev_ops->ndo_change_mtu); res = dev_set_mtu(slave->dev, new_mtu); @@ -3785,8 +3655,7 @@ static int bond_change_mtu(struct net_device *bond_dev, int new_mtu) 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) { + bond_for_each_slave_continue_reverse(bond, slave) { int tmp_res; tmp_res = dev_set_mtu(slave->dev, bond_dev->mtu); @@ -3810,9 +3679,8 @@ static int bond_set_mac_address(struct net_device *bond_dev, void *addr) { struct bonding *bond = netdev_priv(bond_dev); struct sockaddr *sa = addr, tmp_sa; - struct slave *slave, *stop_at; + struct slave *slave; int res = 0; - int i; if (bond->params.mode == BOND_MODE_ALB) return bond_alb_set_mac_address(bond_dev, addr); @@ -3845,7 +3713,7 @@ static int bond_set_mac_address(struct net_device *bond_dev, void *addr) * call to the base driver. */ - bond_for_each_slave(bond, slave, i) { + bond_for_each_slave(bond, slave) { const struct net_device_ops *slave_ops = slave->dev->netdev_ops; pr_debug("slave %p %s\n", slave, slave->dev->name); @@ -3877,8 +3745,7 @@ unwind: tmp_sa.sa_family = bond_dev->type; /* 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) { + bond_for_each_slave_continue_reverse(bond, slave) { int tmp_res; tmp_res = dev_set_mac_address(slave->dev, &tmp_sa); @@ -3891,12 +3758,50 @@ unwind: return res; } +/** + * bond_xmit_slave_id - transmit skb through slave with slave_id + * @bond: bonding device that is transmitting + * @skb: buffer to transmit + * @slave_id: slave id up to slave_cnt-1 through which to transmit + * + * This function tries to transmit through slave with slave_id but in case + * it fails, it tries to find the first available slave for transmission. + * The skb is consumed in all cases, thus the function is void. + */ +void bond_xmit_slave_id(struct bonding *bond, struct sk_buff *skb, int slave_id) +{ + struct slave *slave; + int i = slave_id; + + /* Here we start from the slave with slave_id */ + bond_for_each_slave_rcu(bond, slave) { + if (--i < 0) { + if (slave_can_tx(slave)) { + bond_dev_queue_xmit(bond, skb, slave->dev); + return; + } + } + } + + /* Here we start from the first slave up to slave_id */ + i = slave_id; + bond_for_each_slave_rcu(bond, slave) { + if (--i < 0) + break; + if (slave_can_tx(slave)) { + bond_dev_queue_xmit(bond, skb, slave->dev); + return; + } + } + /* no slave that can tx has been found */ + kfree_skb(skb); +} + static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *bond_dev) { struct bonding *bond = netdev_priv(bond_dev); - struct slave *slave, *start_at; - int i, slave_no, res = 1; struct iphdr *iph = ip_hdr(skb); + struct slave *slave; /* * Start with the curr_active_slave that joined the bond as the @@ -3905,50 +3810,20 @@ static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *bond_dev * send the join/membership reports. The curr_active_slave found * will send all of this type of traffic. */ - if ((iph->protocol == IPPROTO_IGMP) && - (skb->protocol == htons(ETH_P_IP))) { - - read_lock(&bond->curr_slave_lock); - slave = bond->curr_active_slave; - read_unlock(&bond->curr_slave_lock); - - if (!slave) - goto out; + if (iph->protocol == IPPROTO_IGMP && skb->protocol == htons(ETH_P_IP)) { + slave = rcu_dereference(bond->curr_active_slave); + if (slave && slave_can_tx(slave)) + bond_dev_queue_xmit(bond, skb, slave->dev); + else + bond_xmit_slave_id(bond, skb, 0); } else { - /* - * Concurrent TX may collide on rr_tx_counter; we accept - * that as being rare enough not to justify using an - * atomic op here. - */ - slave_no = bond->rr_tx_counter++ % bond->slave_cnt; - - bond_for_each_slave(bond, slave, i) { - slave_no--; - if (slave_no < 0) - break; - } - } - - start_at = slave; - bond_for_each_slave_from(bond, slave, i, start_at) { - if (IS_UP(slave->dev) && - (slave->link == BOND_LINK_UP) && - bond_is_active_slave(slave)) { - res = bond_dev_queue_xmit(bond, skb, slave->dev); - break; - } - } - -out: - if (res) { - /* no suitable interface, frame not sent */ - kfree_skb(skb); + bond_xmit_slave_id(bond, skb, + bond->rr_tx_counter++ % bond->slave_cnt); } return NETDEV_TX_OK; } - /* * in active-backup mode, we know that bond->curr_active_slave is always valid if * the bond has a usable interface. @@ -3956,18 +3831,12 @@ out: static int bond_xmit_activebackup(struct sk_buff *skb, struct net_device *bond_dev) { struct bonding *bond = netdev_priv(bond_dev); - int res = 1; - - read_lock(&bond->curr_slave_lock); - - if (bond->curr_active_slave) - res = bond_dev_queue_xmit(bond, skb, - bond->curr_active_slave->dev); - - read_unlock(&bond->curr_slave_lock); + struct slave *slave; - if (res) - /* no suitable interface, frame not sent */ + slave = rcu_dereference(bond->curr_active_slave); + if (slave) + bond_dev_queue_xmit(bond, skb, slave->dev); + else kfree_skb(skb); return NETDEV_TX_OK; @@ -3981,87 +3850,39 @@ static int bond_xmit_activebackup(struct sk_buff *skb, struct net_device *bond_d static int bond_xmit_xor(struct sk_buff *skb, struct net_device *bond_dev) { struct bonding *bond = netdev_priv(bond_dev); - struct slave *slave, *start_at; - int slave_no; - int i; - int res = 1; - slave_no = bond->xmit_hash_policy(skb, bond->slave_cnt); - - bond_for_each_slave(bond, slave, i) { - slave_no--; - if (slave_no < 0) - break; - } - - start_at = slave; - - bond_for_each_slave_from(bond, slave, i, start_at) { - if (IS_UP(slave->dev) && - (slave->link == BOND_LINK_UP) && - bond_is_active_slave(slave)) { - res = bond_dev_queue_xmit(bond, skb, slave->dev); - break; - } - } - - if (res) { - /* no suitable interface, frame not sent */ - kfree_skb(skb); - } + bond_xmit_slave_id(bond, skb, + bond->xmit_hash_policy(skb, bond->slave_cnt)); return NETDEV_TX_OK; } -/* - * in broadcast mode, we send everything to all usable interfaces. - */ +/* in broadcast mode, we send everything to all usable interfaces. */ static int bond_xmit_broadcast(struct sk_buff *skb, struct net_device *bond_dev) { struct bonding *bond = netdev_priv(bond_dev); - struct slave *slave, *start_at; - struct net_device *tx_dev = NULL; - int i; - int res = 1; - - read_lock(&bond->curr_slave_lock); - start_at = bond->curr_active_slave; - read_unlock(&bond->curr_slave_lock); - - if (!start_at) - goto out; + struct slave *slave = NULL; - bond_for_each_slave_from(bond, slave, i, start_at) { - if (IS_UP(slave->dev) && - (slave->link == BOND_LINK_UP) && - bond_is_active_slave(slave)) { - if (tx_dev) { - struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC); - if (!skb2) { - pr_err("%s: Error: bond_xmit_broadcast(): skb_clone() failed\n", - bond_dev->name); - continue; - } + bond_for_each_slave_rcu(bond, slave) { + if (bond_is_last_slave(bond, slave)) + break; + if (IS_UP(slave->dev) && slave->link == BOND_LINK_UP) { + struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC); - res = bond_dev_queue_xmit(bond, skb2, tx_dev); - if (res) { - kfree_skb(skb2); - continue; - } + if (!skb2) { + pr_err("%s: Error: bond_xmit_broadcast(): skb_clone() failed\n", + bond_dev->name); + continue; } - tx_dev = slave->dev; + /* bond_dev_queue_xmit always returns 0 */ + bond_dev_queue_xmit(bond, skb2, slave->dev); } } - - if (tx_dev) - res = bond_dev_queue_xmit(bond, skb, tx_dev); - -out: - if (res) - /* no suitable interface, frame not sent */ + if (slave && IS_UP(slave->dev) && slave->link == BOND_LINK_UP) + bond_dev_queue_xmit(bond, skb, slave->dev); + else kfree_skb(skb); - /* frame sent to all suitable interfaces */ return NETDEV_TX_OK; } @@ -4089,15 +3910,15 @@ static void bond_set_xmit_hash_policy(struct bonding *bond) static inline int bond_slave_override(struct bonding *bond, struct sk_buff *skb) { - int i, res = 1; struct slave *slave = NULL; struct slave *check_slave; + int res = 1; if (!skb->queue_mapping) return 1; /* Find out if any slaves have the same mapping as this skb. */ - bond_for_each_slave(bond, check_slave, i) { + bond_for_each_slave_rcu(bond, check_slave) { if (check_slave->queue_id == skb->queue_mapping) { slave = check_slave; break; @@ -4182,14 +4003,12 @@ static netdev_tx_t bond_start_xmit(struct sk_buff *skb, struct net_device *dev) if (is_netpoll_tx_blocked(dev)) return NETDEV_TX_BUSY; - read_lock(&bond->lock); - - if (bond->slave_cnt) + rcu_read_lock(); + if (!list_empty(&bond->slave_list)) ret = __bond_start_xmit(skb, dev); else kfree_skb(skb); - - read_unlock(&bond->lock); + rcu_read_unlock(); return ret; } @@ -4230,9 +4049,8 @@ 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; + struct slave *slave; ecmd->duplex = DUPLEX_UNKNOWN; ecmd->port = PORT_OTHER; @@ -4243,7 +4061,7 @@ static int bond_ethtool_get_settings(struct net_device *bond_dev, * this is an accurate maximum. */ read_lock(&bond->lock); - bond_for_each_slave(bond, slave, i) { + bond_for_each_slave(bond, slave) { if (SLAVE_IS_OK(slave)) { if (slave->speed != SPEED_UNKNOWN) speed += slave->speed; @@ -4254,6 +4072,7 @@ static int bond_ethtool_get_settings(struct net_device *bond_dev, } ethtool_cmd_speed_set(ecmd, speed ? : SPEED_UNKNOWN); read_unlock(&bond->lock); + return 0; } @@ -4317,7 +4136,7 @@ static void bond_setup(struct net_device *bond_dev) /* initialize rwlocks */ rwlock_init(&bond->lock); rwlock_init(&bond->curr_slave_lock); - + INIT_LIST_HEAD(&bond->slave_list); bond->params = bonding_defaults; /* Initialize pointers */ @@ -4374,13 +4193,14 @@ static void bond_setup(struct net_device *bond_dev) static void bond_uninit(struct net_device *bond_dev) { struct bonding *bond = netdev_priv(bond_dev); + struct slave *slave, *tmp_slave; struct vlan_entry *vlan, *tmp; bond_netpoll_cleanup(bond_dev); /* Release the bonded slaves */ - while (bond->first_slave != NULL) - __bond_release_one(bond_dev, bond->first_slave->dev, true); + list_for_each_entry_safe(slave, tmp_slave, &bond->slave_list, list) + __bond_release_one(bond_dev, slave->dev, true); pr_info("%s: released all slaves\n", bond_dev->name); list_del(&bond->bond_list); |