diff options
author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2012-03-20 04:02:01 +0400 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2012-03-20 04:02:01 +0400 |
commit | 10ce3cc919f50c2043b41ca968b43c26a3672600 (patch) | |
tree | ea409366a5208aced495bc0516a08b81fd43222e /drivers/net/bonding | |
parent | 24e3e5ae1e4c2a3a32f5b1f96b4e3fd721806acd (diff) | |
parent | 5c6a7a62c130afef3d61c1dee153012231ff5cd9 (diff) | |
download | linux-10ce3cc919f50c2043b41ca968b43c26a3672600.tar.xz |
Merge branch 'next' into for-linus
Diffstat (limited to 'drivers/net/bonding')
-rw-r--r-- | drivers/net/bonding/bond_alb.c | 139 | ||||
-rw-r--r-- | drivers/net/bonding/bond_ipv6.c | 225 | ||||
-rw-r--r-- | drivers/net/bonding/bond_main.c | 116 | ||||
-rw-r--r-- | drivers/net/bonding/bond_sysfs.c | 1 |
4 files changed, 135 insertions, 346 deletions
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index 106b88a04738..f820b26b9db3 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -99,16 +99,26 @@ static inline u8 _simple_hash(const u8 *hash_start, int hash_size) /*********************** tlb specific functions ***************************/ -static inline void _lock_tx_hashtbl(struct bonding *bond) +static inline void _lock_tx_hashtbl_bh(struct bonding *bond) { spin_lock_bh(&(BOND_ALB_INFO(bond).tx_hashtbl_lock)); } -static inline void _unlock_tx_hashtbl(struct bonding *bond) +static inline void _unlock_tx_hashtbl_bh(struct bonding *bond) { spin_unlock_bh(&(BOND_ALB_INFO(bond).tx_hashtbl_lock)); } +static inline void _lock_tx_hashtbl(struct bonding *bond) +{ + spin_lock(&(BOND_ALB_INFO(bond).tx_hashtbl_lock)); +} + +static inline void _unlock_tx_hashtbl(struct bonding *bond) +{ + spin_unlock(&(BOND_ALB_INFO(bond).tx_hashtbl_lock)); +} + /* Caller must hold tx_hashtbl lock */ static inline void tlb_init_table_entry(struct tlb_client_info *entry, int save_load) { @@ -129,14 +139,13 @@ static inline void tlb_init_slave(struct slave *slave) SLAVE_TLB_INFO(slave).head = TLB_NULL_INDEX; } -/* Caller must hold bond lock for read */ -static void tlb_clear_slave(struct bonding *bond, struct slave *slave, int save_load) +/* Caller must hold bond lock for read, BH disabled */ +static void __tlb_clear_slave(struct bonding *bond, struct slave *slave, + int save_load) { struct tlb_client_info *tx_hash_table; u32 index; - _lock_tx_hashtbl(bond); - /* clear slave from tx_hashtbl */ tx_hash_table = BOND_ALB_INFO(bond).tx_hashtbl; @@ -151,8 +160,15 @@ static void tlb_clear_slave(struct bonding *bond, struct slave *slave, int save_ } tlb_init_slave(slave); +} - _unlock_tx_hashtbl(bond); +/* Caller must hold bond lock for read */ +static void tlb_clear_slave(struct bonding *bond, struct slave *slave, + int save_load) +{ + _lock_tx_hashtbl_bh(bond); + __tlb_clear_slave(bond, slave, save_load); + _unlock_tx_hashtbl_bh(bond); } /* Must be called before starting the monitor timer */ @@ -169,7 +185,7 @@ static int tlb_initialize(struct bonding *bond) bond->dev->name); return -1; } - _lock_tx_hashtbl(bond); + _lock_tx_hashtbl_bh(bond); bond_info->tx_hashtbl = new_hashtbl; @@ -177,7 +193,7 @@ static int tlb_initialize(struct bonding *bond) tlb_init_table_entry(&bond_info->tx_hashtbl[i], 0); } - _unlock_tx_hashtbl(bond); + _unlock_tx_hashtbl_bh(bond); return 0; } @@ -187,12 +203,12 @@ static void tlb_deinitialize(struct bonding *bond) { struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); - _lock_tx_hashtbl(bond); + _lock_tx_hashtbl_bh(bond); kfree(bond_info->tx_hashtbl); bond_info->tx_hashtbl = NULL; - _unlock_tx_hashtbl(bond); + _unlock_tx_hashtbl_bh(bond); } static long long compute_gap(struct slave *slave) @@ -226,15 +242,13 @@ static struct slave *tlb_get_least_loaded_slave(struct bonding *bond) return least_loaded; } -/* Caller must hold bond lock for read */ -static struct slave *tlb_choose_channel(struct bonding *bond, u32 hash_index, u32 skb_len) +static struct slave *__tlb_choose_channel(struct bonding *bond, u32 hash_index, + u32 skb_len) { struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); struct tlb_client_info *hash_table; struct slave *assigned_slave; - _lock_tx_hashtbl(bond); - hash_table = bond_info->tx_hashtbl; assigned_slave = hash_table[hash_index].tx_slave; if (!assigned_slave) { @@ -263,22 +277,46 @@ static struct slave *tlb_choose_channel(struct bonding *bond, u32 hash_index, u3 hash_table[hash_index].tx_bytes += skb_len; } - _unlock_tx_hashtbl(bond); - return assigned_slave; } +/* Caller must hold bond lock for read */ +static struct slave *tlb_choose_channel(struct bonding *bond, u32 hash_index, + u32 skb_len) +{ + struct slave *tx_slave; + /* + * We don't need to disable softirq here, becase + * tlb_choose_channel() is only called by bond_alb_xmit() + * which already has softirq disabled. + */ + _lock_tx_hashtbl(bond); + tx_slave = __tlb_choose_channel(bond, hash_index, skb_len); + _unlock_tx_hashtbl(bond); + return tx_slave; +} + /*********************** rlb specific functions ***************************/ -static inline void _lock_rx_hashtbl(struct bonding *bond) +static inline void _lock_rx_hashtbl_bh(struct bonding *bond) { spin_lock_bh(&(BOND_ALB_INFO(bond).rx_hashtbl_lock)); } -static inline void _unlock_rx_hashtbl(struct bonding *bond) +static inline void _unlock_rx_hashtbl_bh(struct bonding *bond) { spin_unlock_bh(&(BOND_ALB_INFO(bond).rx_hashtbl_lock)); } +static inline void _lock_rx_hashtbl(struct bonding *bond) +{ + spin_lock(&(BOND_ALB_INFO(bond).rx_hashtbl_lock)); +} + +static inline void _unlock_rx_hashtbl(struct bonding *bond) +{ + spin_unlock(&(BOND_ALB_INFO(bond).rx_hashtbl_lock)); +} + /* when an ARP REPLY is received from a client update its info * in the rx_hashtbl */ @@ -288,7 +326,7 @@ static void rlb_update_entry_from_arp(struct bonding *bond, struct arp_pkt *arp) struct rlb_client_info *client_info; u32 hash_index; - _lock_rx_hashtbl(bond); + _lock_rx_hashtbl_bh(bond); hash_index = _simple_hash((u8*)&(arp->ip_src), sizeof(arp->ip_src)); client_info = &(bond_info->rx_hashtbl[hash_index]); @@ -303,7 +341,7 @@ static void rlb_update_entry_from_arp(struct bonding *bond, struct arp_pkt *arp) bond_info->rx_ntt = 1; } - _unlock_rx_hashtbl(bond); + _unlock_rx_hashtbl_bh(bond); } static void rlb_arp_recv(struct sk_buff *skb, struct bonding *bond, @@ -401,7 +439,7 @@ static void rlb_clear_slave(struct bonding *bond, struct slave *slave) u32 index, next_index; /* clear slave from rx_hashtbl */ - _lock_rx_hashtbl(bond); + _lock_rx_hashtbl_bh(bond); rx_hash_table = bond_info->rx_hashtbl; index = bond_info->rx_hashtbl_head; @@ -432,7 +470,7 @@ static void rlb_clear_slave(struct bonding *bond, struct slave *slave) } } - _unlock_rx_hashtbl(bond); + _unlock_rx_hashtbl_bh(bond); write_lock_bh(&bond->curr_slave_lock); @@ -489,7 +527,7 @@ static void rlb_update_rx_clients(struct bonding *bond) struct rlb_client_info *client_info; u32 hash_index; - _lock_rx_hashtbl(bond); + _lock_rx_hashtbl_bh(bond); hash_index = bond_info->rx_hashtbl_head; for (; hash_index != RLB_NULL_INDEX; hash_index = client_info->next) { @@ -507,7 +545,7 @@ static void rlb_update_rx_clients(struct bonding *bond) */ bond_info->rlb_update_delay_counter = RLB_UPDATE_DELAY; - _unlock_rx_hashtbl(bond); + _unlock_rx_hashtbl_bh(bond); } /* The slave was assigned a new mac address - update the clients */ @@ -518,7 +556,7 @@ static void rlb_req_update_slave_clients(struct bonding *bond, struct slave *sla int ntt = 0; u32 hash_index; - _lock_rx_hashtbl(bond); + _lock_rx_hashtbl_bh(bond); hash_index = bond_info->rx_hashtbl_head; for (; hash_index != RLB_NULL_INDEX; hash_index = client_info->next) { @@ -538,7 +576,7 @@ static void rlb_req_update_slave_clients(struct bonding *bond, struct slave *sla bond_info->rlb_update_retry_counter = RLB_UPDATE_RETRY; } - _unlock_rx_hashtbl(bond); + _unlock_rx_hashtbl_bh(bond); } /* mark all clients using src_ip to be updated */ @@ -709,7 +747,7 @@ static void rlb_rebalance(struct bonding *bond) int ntt; u32 hash_index; - _lock_rx_hashtbl(bond); + _lock_rx_hashtbl_bh(bond); ntt = 0; hash_index = bond_info->rx_hashtbl_head; @@ -727,7 +765,7 @@ static void rlb_rebalance(struct bonding *bond) if (ntt) { bond_info->rx_ntt = 1; } - _unlock_rx_hashtbl(bond); + _unlock_rx_hashtbl_bh(bond); } /* Caller must hold rx_hashtbl lock */ @@ -751,7 +789,7 @@ static int rlb_initialize(struct bonding *bond) bond->dev->name); return -1; } - _lock_rx_hashtbl(bond); + _lock_rx_hashtbl_bh(bond); bond_info->rx_hashtbl = new_hashtbl; @@ -761,7 +799,7 @@ static int rlb_initialize(struct bonding *bond) rlb_init_table_entry(bond_info->rx_hashtbl + i); } - _unlock_rx_hashtbl(bond); + _unlock_rx_hashtbl_bh(bond); /* register to receive ARPs */ bond->recv_probe = rlb_arp_recv; @@ -773,13 +811,13 @@ static void rlb_deinitialize(struct bonding *bond) { struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); - _lock_rx_hashtbl(bond); + _lock_rx_hashtbl_bh(bond); kfree(bond_info->rx_hashtbl); bond_info->rx_hashtbl = NULL; bond_info->rx_hashtbl_head = RLB_NULL_INDEX; - _unlock_rx_hashtbl(bond); + _unlock_rx_hashtbl_bh(bond); } static void rlb_clear_vlan(struct bonding *bond, unsigned short vlan_id) @@ -787,7 +825,7 @@ static void rlb_clear_vlan(struct bonding *bond, unsigned short vlan_id) struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); u32 curr_index; - _lock_rx_hashtbl(bond); + _lock_rx_hashtbl_bh(bond); curr_index = bond_info->rx_hashtbl_head; while (curr_index != RLB_NULL_INDEX) { @@ -812,7 +850,7 @@ static void rlb_clear_vlan(struct bonding *bond, unsigned short vlan_id) curr_index = next_index; } - _unlock_rx_hashtbl(bond); + _unlock_rx_hashtbl_bh(bond); } /*********************** tlb/rlb shared functions *********************/ @@ -871,16 +909,12 @@ static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[]) } } -/* hw is a boolean parameter that determines whether we should try and - * set the hw address of the device as well as the hw address of the - * net_device - */ -static int alb_set_slave_mac_addr(struct slave *slave, u8 addr[], int hw) +static int alb_set_slave_mac_addr(struct slave *slave, u8 addr[]) { struct net_device *dev = slave->dev; struct sockaddr s_addr; - if (!hw) { + if (slave->bond->params.mode == BOND_MODE_TLB) { memcpy(dev->dev_addr, addr, dev->addr_len); return 0; } @@ -910,8 +944,8 @@ static void alb_swap_mac_addr(struct bonding *bond, struct slave *slave1, struct u8 tmp_mac_addr[ETH_ALEN]; memcpy(tmp_mac_addr, slave1->dev->dev_addr, ETH_ALEN); - alb_set_slave_mac_addr(slave1, slave2->dev->dev_addr, bond->alb_info.rlb_enabled); - alb_set_slave_mac_addr(slave2, tmp_mac_addr, bond->alb_info.rlb_enabled); + alb_set_slave_mac_addr(slave1, slave2->dev->dev_addr); + alb_set_slave_mac_addr(slave2, tmp_mac_addr); } @@ -1058,8 +1092,7 @@ static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slav /* Try setting slave mac to bond address and fall-through to code handling that situation below... */ - alb_set_slave_mac_addr(slave, bond->dev->dev_addr, - bond->alb_info.rlb_enabled); + alb_set_slave_mac_addr(slave, bond->dev->dev_addr); } /* The slave's address is equal to the address of the bond. @@ -1095,8 +1128,7 @@ static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slav } if (free_mac_slave) { - alb_set_slave_mac_addr(slave, free_mac_slave->perm_hwaddr, - bond->alb_info.rlb_enabled); + alb_set_slave_mac_addr(slave, free_mac_slave->perm_hwaddr); pr_warning("%s: Warning: the hw address of slave %s is in use by the bond; giving it the hw address of %s\n", bond->dev->name, slave->dev->name, @@ -1320,7 +1352,9 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev) res = bond_dev_queue_xmit(bond, skb, tx_slave->dev); } else { if (tx_slave) { - tlb_clear_slave(bond, tx_slave, 0); + _lock_tx_hashtbl(bond); + __tlb_clear_slave(bond, tx_slave, 0); + _unlock_tx_hashtbl(bond); } } @@ -1451,8 +1485,7 @@ int bond_alb_init_slave(struct bonding *bond, struct slave *slave) { int res; - res = alb_set_slave_mac_addr(slave, slave->perm_hwaddr, - bond->alb_info.rlb_enabled); + res = alb_set_slave_mac_addr(slave, slave->perm_hwaddr); if (res) { return res; } @@ -1603,8 +1636,7 @@ void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave alb_swap_mac_addr(bond, swap_slave, new_slave); } else { /* set the new_slave to the bond mac address */ - alb_set_slave_mac_addr(new_slave, bond->dev->dev_addr, - bond->alb_info.rlb_enabled); + alb_set_slave_mac_addr(new_slave, bond->dev->dev_addr); } if (swap_slave) { @@ -1664,8 +1696,7 @@ int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr) alb_swap_mac_addr(bond, swap_slave, bond->curr_active_slave); alb_fasten_mac_swap(bond, swap_slave, bond->curr_active_slave); } else { - alb_set_slave_mac_addr(bond->curr_active_slave, bond_dev->dev_addr, - bond->alb_info.rlb_enabled); + alb_set_slave_mac_addr(bond->curr_active_slave, bond_dev->dev_addr); read_lock(&bond->lock); alb_send_learning_packets(bond->curr_active_slave, bond_dev->dev_addr); diff --git a/drivers/net/bonding/bond_ipv6.c b/drivers/net/bonding/bond_ipv6.c deleted file mode 100644 index 027a0ee7d85b..000000000000 --- a/drivers/net/bonding/bond_ipv6.c +++ /dev/null @@ -1,225 +0,0 @@ -/* - * Copyright(c) 2008 Hewlett-Packard Development Company, L.P. - * - * 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. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * The full GNU General Public License is included in this distribution in the - * file called LICENSE. - * - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include <linux/types.h> -#include <linux/if_vlan.h> -#include <net/ipv6.h> -#include <net/ndisc.h> -#include <net/addrconf.h> -#include <net/netns/generic.h> -#include "bonding.h" - -/* - * Assign bond->master_ipv6 to the next IPv6 address in the list, or - * zero it out if there are none. - */ -static void bond_glean_dev_ipv6(struct net_device *dev, struct in6_addr *addr) -{ - struct inet6_dev *idev; - - if (!dev) - return; - - idev = in6_dev_get(dev); - if (!idev) - return; - - read_lock_bh(&idev->lock); - if (!list_empty(&idev->addr_list)) { - struct inet6_ifaddr *ifa - = list_first_entry(&idev->addr_list, - struct inet6_ifaddr, if_list); - ipv6_addr_copy(addr, &ifa->addr); - } else - ipv6_addr_set(addr, 0, 0, 0, 0); - - read_unlock_bh(&idev->lock); - - in6_dev_put(idev); -} - -static void bond_na_send(struct net_device *slave_dev, - struct in6_addr *daddr, - int router, - unsigned short vlan_id) -{ - struct in6_addr mcaddr; - struct icmp6hdr icmp6h = { - .icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT, - }; - struct sk_buff *skb; - - icmp6h.icmp6_router = router; - icmp6h.icmp6_solicited = 0; - icmp6h.icmp6_override = 1; - - addrconf_addr_solict_mult(daddr, &mcaddr); - - pr_debug("ipv6 na on slave %s: dest %pI6, src %pI6\n", - slave_dev->name, &mcaddr, daddr); - - skb = ndisc_build_skb(slave_dev, &mcaddr, daddr, &icmp6h, daddr, - ND_OPT_TARGET_LL_ADDR); - - if (!skb) { - pr_err("NA packet allocation failed\n"); - return; - } - - if (vlan_id) { - /* The Ethernet header is not present yet, so it is - * too early to insert a VLAN tag. Force use of an - * out-of-line tag here and let dev_hard_start_xmit() - * insert it if the slave hardware can't. - */ - skb = __vlan_hwaccel_put_tag(skb, vlan_id); - if (!skb) { - pr_err("failed to insert VLAN tag\n"); - return; - } - } - - ndisc_send_skb(skb, slave_dev, NULL, &mcaddr, daddr, &icmp6h); -} - -/* - * Kick out an unsolicited Neighbor Advertisement for an IPv6 address on - * the bonding master. This will help the switch learn our address - * if in active-backup mode. - * - * Caller must hold curr_slave_lock for read or better - */ -void bond_send_unsolicited_na(struct bonding *bond) -{ - struct slave *slave = bond->curr_active_slave; - struct vlan_entry *vlan; - struct inet6_dev *idev; - int is_router; - - pr_debug("%s: bond %s slave %s\n", bond->dev->name, - __func__, slave ? slave->dev->name : "NULL"); - - if (!slave || !bond->send_unsol_na || - test_bit(__LINK_STATE_LINKWATCH_PENDING, &slave->dev->state)) - return; - - bond->send_unsol_na--; - - idev = in6_dev_get(bond->dev); - if (!idev) - return; - - is_router = !!idev->cnf.forwarding; - - in6_dev_put(idev); - - if (!ipv6_addr_any(&bond->master_ipv6)) - bond_na_send(slave->dev, &bond->master_ipv6, is_router, 0); - - list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { - if (!ipv6_addr_any(&vlan->vlan_ipv6)) { - bond_na_send(slave->dev, &vlan->vlan_ipv6, is_router, - vlan->vlan_id); - } - } -} - -/* - * bond_inet6addr_event: handle inet6addr notifier chain events. - * - * We keep track of device IPv6 addresses primarily to use as source - * addresses in NS probes. - * - * We track one IPv6 for the main device (if it has one). - */ -static int bond_inet6addr_event(struct notifier_block *this, - unsigned long event, - void *ptr) -{ - struct inet6_ifaddr *ifa = ptr; - struct net_device *vlan_dev, *event_dev = ifa->idev->dev; - struct bonding *bond; - struct vlan_entry *vlan; - struct bond_net *bn = net_generic(dev_net(event_dev), bond_net_id); - - list_for_each_entry(bond, &bn->dev_list, bond_list) { - if (bond->dev == event_dev) { - switch (event) { - case NETDEV_UP: - if (ipv6_addr_any(&bond->master_ipv6)) - ipv6_addr_copy(&bond->master_ipv6, - &ifa->addr); - return NOTIFY_OK; - case NETDEV_DOWN: - if (ipv6_addr_equal(&bond->master_ipv6, - &ifa->addr)) - bond_glean_dev_ipv6(bond->dev, - &bond->master_ipv6); - return NOTIFY_OK; - default: - return NOTIFY_DONE; - } - } - - list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { - rcu_read_lock(); - vlan_dev = __vlan_find_dev_deep(bond->dev, - vlan->vlan_id); - rcu_read_unlock(); - if (vlan_dev == event_dev) { - switch (event) { - case NETDEV_UP: - if (ipv6_addr_any(&vlan->vlan_ipv6)) - ipv6_addr_copy(&vlan->vlan_ipv6, - &ifa->addr); - return NOTIFY_OK; - case NETDEV_DOWN: - if (ipv6_addr_equal(&vlan->vlan_ipv6, - &ifa->addr)) - bond_glean_dev_ipv6(vlan_dev, - &vlan->vlan_ipv6); - return NOTIFY_OK; - default: - return NOTIFY_DONE; - } - } - } - } - return NOTIFY_DONE; -} - -static struct notifier_block bond_inet6addr_notifier = { - .notifier_call = bond_inet6addr_event, -}; - -void bond_register_ipv6_notifier(void) -{ - register_inet6addr_notifier(&bond_inet6addr_notifier); -} - -void bond_unregister_ipv6_notifier(void) -{ - unregister_inet6addr_notifier(&bond_inet6addr_notifier); -} - diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index b0c577256487..435984ad8b2f 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -428,27 +428,34 @@ 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 void 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, uint16_t vid) { struct bonding *bond = netdev_priv(bond_dev); - struct slave *slave; + struct slave *slave, *stop_at; int i, res; bond_for_each_slave(bond, slave, i) { - struct net_device *slave_dev = slave->dev; - const struct net_device_ops *slave_ops = slave_dev->netdev_ops; - - if ((slave_dev->features & NETIF_F_HW_VLAN_FILTER) && - slave_ops->ndo_vlan_rx_add_vid) { - slave_ops->ndo_vlan_rx_add_vid(slave_dev, vid); - } + res = vlan_vid_add(slave->dev, vid); + if (res) + goto unwind; } res = bond_add_vlan(bond, vid); if (res) { pr_err("%s: Error: Failed to add vlan id %d\n", bond_dev->name, vid); + return res; } + + 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) + vlan_vid_del(slave->dev, vid); + + return res; } /** @@ -456,56 +463,48 @@ static void bond_vlan_rx_add_vid(struct net_device *bond_dev, uint16_t vid) * @bond_dev: bonding net device that got called * @vid: vlan id being removed */ -static void 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, uint16_t vid) { struct bonding *bond = netdev_priv(bond_dev); struct slave *slave; int i, res; - bond_for_each_slave(bond, slave, i) { - struct net_device *slave_dev = slave->dev; - const struct net_device_ops *slave_ops = slave_dev->netdev_ops; - - if ((slave_dev->features & NETIF_F_HW_VLAN_FILTER) && - slave_ops->ndo_vlan_rx_kill_vid) { - slave_ops->ndo_vlan_rx_kill_vid(slave_dev, vid); - } - } + bond_for_each_slave(bond, slave, i) + vlan_vid_del(slave->dev, vid); res = bond_del_vlan(bond, vid); if (res) { pr_err("%s: Error: Failed to remove vlan id %d\n", bond_dev->name, vid); + return res; } + + return 0; } static void bond_add_vlans_on_slave(struct bonding *bond, struct net_device *slave_dev) { struct vlan_entry *vlan; - const struct net_device_ops *slave_ops = slave_dev->netdev_ops; - - if (!(slave_dev->features & NETIF_F_HW_VLAN_FILTER) || - !(slave_ops->ndo_vlan_rx_add_vid)) - return; + int res; - list_for_each_entry(vlan, &bond->vlan_list, vlan_list) - slave_ops->ndo_vlan_rx_add_vid(slave_dev, vlan->vlan_id); + list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { + res = vlan_vid_add(slave_dev, 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) { - const struct net_device_ops *slave_ops = slave_dev->netdev_ops; struct vlan_entry *vlan; - if (!(slave_dev->features & NETIF_F_HW_VLAN_FILTER) || - !(slave_ops->ndo_vlan_rx_kill_vid)) - return; - list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { if (!vlan->vlan_id) continue; - slave_ops->ndo_vlan_rx_kill_vid(slave_dev, vlan->vlan_id); + vlan_vid_del(slave_dev, vlan->vlan_id); } } @@ -1325,11 +1324,12 @@ static int bond_sethwaddr(struct net_device *bond_dev, return 0; } -static u32 bond_fix_features(struct net_device *dev, u32 features) +static netdev_features_t bond_fix_features(struct net_device *dev, + netdev_features_t features) { struct slave *slave; struct bonding *bond = netdev_priv(dev); - u32 mask; + netdev_features_t mask; int i; read_lock(&bond->lock); @@ -1363,7 +1363,7 @@ static void bond_compute_features(struct bonding *bond) { struct slave *slave; struct net_device *bond_dev = bond->dev; - u32 vlan_features = BOND_VLAN_FEATURES; + netdev_features_t vlan_features = BOND_VLAN_FEATURES; unsigned short max_hard_header_len = ETH_HLEN; int i; @@ -1822,7 +1822,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) "but new slave device does not support netpoll.\n", bond_dev->name); res = -EBUSY; - goto err_close; + goto err_detach; } } #endif @@ -1831,7 +1831,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) res = bond_create_slave_symlinks(bond_dev, slave_dev); if (res) - goto err_close; + goto err_detach; res = netdev_rx_handler_register(slave_dev, bond_handle_frame, new_slave); @@ -1852,6 +1852,11 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) err_dest_symlinks: bond_destroy_slave_symlinks(bond_dev, slave_dev); +err_detach: + write_lock_bh(&bond->lock); + bond_detach_slave(bond, new_slave); + write_unlock_bh(&bond->lock); + err_close: dev_close(slave_dev); @@ -1897,7 +1902,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) struct bonding *bond = netdev_priv(bond_dev); struct slave *slave, *oldcurrent; struct sockaddr addr; - u32 old_features = bond_dev->features; + netdev_features_t old_features = bond_dev->features; /* slave is not a slave or master is not master of this slave */ if (!(slave_dev->flags & IFF_SLAVE) || @@ -2553,30 +2558,6 @@ re_arm: } } -static __be32 bond_glean_dev_ip(struct net_device *dev) -{ - struct in_device *idev; - struct in_ifaddr *ifa; - __be32 addr = 0; - - if (!dev) - return 0; - - rcu_read_lock(); - idev = __in_dev_get_rcu(dev); - if (!idev) - goto out; - - ifa = idev->ifa_list; - if (!ifa) - goto out; - - addr = ifa->ifa_local; -out: - rcu_read_unlock(); - return addr; -} - static int bond_has_this_ip(struct bonding *bond, __be32 ip) { struct vlan_entry *vlan; @@ -3322,6 +3303,10 @@ static int bond_inetaddr_event(struct notifier_block *this, unsigned long event, struct bonding *bond; struct vlan_entry *vlan; + /* we only care about primary address */ + if(ifa->ifa_flags & IFA_F_SECONDARY) + return NOTIFY_DONE; + list_for_each_entry(bond, &bn->dev_list, bond_list) { if (bond->dev == event_dev) { switch (event) { @@ -3329,7 +3314,7 @@ static int bond_inetaddr_event(struct notifier_block *this, unsigned long event, bond->master_ip = ifa->ifa_local; return NOTIFY_OK; case NETDEV_DOWN: - bond->master_ip = bond_glean_dev_ip(bond->dev); + bond->master_ip = 0; return NOTIFY_OK; default: return NOTIFY_DONE; @@ -3345,8 +3330,7 @@ static int bond_inetaddr_event(struct notifier_block *this, unsigned long event, vlan->vlan_ip = ifa->ifa_local; return NOTIFY_OK; case NETDEV_DOWN: - vlan->vlan_ip = - bond_glean_dev_ip(vlan_dev); + vlan->vlan_ip = 0; return NOTIFY_OK; default: return NOTIFY_DONE; @@ -4360,7 +4344,7 @@ static void bond_setup(struct net_device *bond_dev) NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER; - bond_dev->hw_features &= ~(NETIF_F_ALL_CSUM & ~NETIF_F_NO_CSUM); + bond_dev->hw_features &= ~(NETIF_F_ALL_CSUM & ~NETIF_F_HW_CSUM); bond_dev->features |= bond_dev->hw_features; } diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index 4ef7e2fd9fe6..aef42f045320 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -26,7 +26,6 @@ #include <linux/module.h> #include <linux/device.h> #include <linux/sched.h> -#include <linux/sysdev.h> #include <linux/fs.h> #include <linux/types.h> #include <linux/string.h> |