11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright(c) 1999 - 2004 Intel Corporation. All rights reserved.
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify it
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * under the terms of the GNU General Public License as published by the
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Free Software Foundation; either version 2 of the License, or
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (at your option) any later version.
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is distributed in the hope that it will be useful, but
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for more details.
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * You should have received a copy of the GNU General Public License along
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * with this program; if not, write to the Free Software Foundation, Inc.,
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The full GNU General Public License is included in this distribution in the
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * file called LICENSE.
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23a4aee5c808fc5bf6889c9012217841eb3fd91a6aJoe Perches#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
24a4aee5c808fc5bf6889c9012217841eb3fd91a6aJoe Perches
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/skbuff.h>
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/netdevice.h>
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/etherdevice.h>
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pkt_sched.h>
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/spinlock.h>
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h>
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/timer.h>
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ip.h>
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ipv6.h>
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/if_arp.h>
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/if_ether.h>
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/if_bonding.h>
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/if_vlan.h>
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/in.h>
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/ipx.h>
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/arp.h>
412d1ea19da0e84117d3ebbad981e4664bef03152eVlad Yasevich#include <net/ipv6.h>
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/byteorder.h>
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "bonding.h"
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "bond_alb.h"
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
48885a136c52a8871175477baf3903e1c38751b35aEric Dumazet#ifndef __long_aligned
49885a136c52a8871175477baf3903e1c38751b35aEric Dumazet#define __long_aligned __attribute__((aligned((sizeof(long)))))
50885a136c52a8871175477baf3903e1c38751b35aEric Dumazet#endif
51885a136c52a8871175477baf3903e1c38751b35aEric Dumazetstatic const u8 mac_bcast[ETH_ALEN] __long_aligned = {
52885a136c52a8871175477baf3903e1c38751b35aEric Dumazet	0xff, 0xff, 0xff, 0xff, 0xff, 0xff
53885a136c52a8871175477baf3903e1c38751b35aEric Dumazet};
54885a136c52a8871175477baf3903e1c38751b35aEric Dumazetstatic const u8 mac_v6_allmcast[ETH_ALEN] __long_aligned = {
55885a136c52a8871175477baf3903e1c38751b35aEric Dumazet	0x33, 0x33, 0x00, 0x00, 0x00, 0x01
56885a136c52a8871175477baf3903e1c38751b35aEric Dumazet};
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const int alb_delta_in_ticks = HZ / ALB_TIMER_TICKS_PER_SEC;
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#pragma pack(1)
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct learning_pkt {
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 mac_dst[ETH_ALEN];
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 mac_src[ETH_ALEN];
63d3bb52b0948cf118131c951c5a34a2d4d0246171Al Viro	__be16 type;
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 padding[ETH_ZLEN - ETH_HLEN];
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct arp_pkt {
68d3bb52b0948cf118131c951c5a34a2d4d0246171Al Viro	__be16  hw_addr_space;
69d3bb52b0948cf118131c951c5a34a2d4d0246171Al Viro	__be16  prot_addr_space;
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8      hw_addr_len;
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8      prot_addr_len;
72d3bb52b0948cf118131c951c5a34a2d4d0246171Al Viro	__be16  op_code;
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8      mac_src[ETH_ALEN];	/* sender hardware address */
74d3bb52b0948cf118131c951c5a34a2d4d0246171Al Viro	__be32  ip_src;			/* sender IP address */
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8      mac_dst[ETH_ALEN];	/* target hardware address */
76d3bb52b0948cf118131c951c5a34a2d4d0246171Al Viro	__be32  ip_dst;			/* target IP address */
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#pragma pack()
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
80a16aeb36239ce612699ed64a75a03c88cbc657e8Arnaldo Carvalho de Melostatic inline struct arp_pkt *arp_pkt(const struct sk_buff *skb)
81a16aeb36239ce612699ed64a75a03c88cbc657e8Arnaldo Carvalho de Melo{
82d56f90a7c96da5187f0cdf07ee7434fe6aa78bbcArnaldo Carvalho de Melo	return (struct arp_pkt *)skb_network_header(skb);
83a16aeb36239ce612699ed64a75a03c88cbc657e8Arnaldo Carvalho de Melo}
84a16aeb36239ce612699ed64a75a03c88cbc657e8Arnaldo Carvalho de Melo
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Forward declaration */
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void alb_send_learning_packets(struct slave *slave, u8 mac_addr[]);
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
88eddc9ec53be2ecdbf4efe0efd4a83052594f0ac0Arnaldo Carvalho de Melostatic inline u8 _simple_hash(const u8 *hash_start, int hash_size)
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 hash = 0;
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < hash_size; i++) {
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		hash ^= hash_start[i];
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return hash;
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*********************** tlb specific functions ***************************/
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
102f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarovstatic inline void _lock_tx_hashtbl_bh(struct bonding *bond)
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1046603a6f25e4bca922a7dfbf0bf03072d98850176Jay Vosburgh	spin_lock_bh(&(BOND_ALB_INFO(bond).tx_hashtbl_lock));
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
107f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarovstatic inline void _unlock_tx_hashtbl_bh(struct bonding *bond)
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1096603a6f25e4bca922a7dfbf0bf03072d98850176Jay Vosburgh	spin_unlock_bh(&(BOND_ALB_INFO(bond).tx_hashtbl_lock));
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
112f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarovstatic inline void _lock_tx_hashtbl(struct bonding *bond)
113f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarov{
114f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarov	spin_lock(&(BOND_ALB_INFO(bond).tx_hashtbl_lock));
115f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarov}
116f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarov
117f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarovstatic inline void _unlock_tx_hashtbl(struct bonding *bond)
118f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarov{
119f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarov	spin_unlock(&(BOND_ALB_INFO(bond).tx_hashtbl_lock));
120f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarov}
121f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarov
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Caller must hold tx_hashtbl lock */
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void tlb_init_table_entry(struct tlb_client_info *entry, int save_load)
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (save_load) {
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		entry->load_history = 1 + entry->tx_bytes /
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      BOND_TLB_REBALANCE_INTERVAL;
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		entry->tx_bytes = 0;
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	entry->tx_slave = NULL;
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	entry->next = TLB_NULL_INDEX;
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	entry->prev = TLB_NULL_INDEX;
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void tlb_init_slave(struct slave *slave)
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SLAVE_TLB_INFO(slave).load = 0;
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SLAVE_TLB_INFO(slave).head = TLB_NULL_INDEX;
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
142f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarov/* Caller must hold bond lock for read, BH disabled */
143f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarovstatic void __tlb_clear_slave(struct bonding *bond, struct slave *slave,
144f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarov			 int save_load)
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tlb_client_info *tx_hash_table;
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 index;
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* clear slave from tx_hashtbl */
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tx_hash_table = BOND_ALB_INFO(bond).tx_hashtbl;
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
152ce39a800ea87c655de49af021c8b20ee323cb40dAndy Gospodarek	/* skip this if we've already freed the tx hash table */
153ce39a800ea87c655de49af021c8b20ee323cb40dAndy Gospodarek	if (tx_hash_table) {
154ce39a800ea87c655de49af021c8b20ee323cb40dAndy Gospodarek		index = SLAVE_TLB_INFO(slave).head;
155ce39a800ea87c655de49af021c8b20ee323cb40dAndy Gospodarek		while (index != TLB_NULL_INDEX) {
156ce39a800ea87c655de49af021c8b20ee323cb40dAndy Gospodarek			u32 next_index = tx_hash_table[index].next;
157ce39a800ea87c655de49af021c8b20ee323cb40dAndy Gospodarek			tlb_init_table_entry(&tx_hash_table[index], save_load);
158ce39a800ea87c655de49af021c8b20ee323cb40dAndy Gospodarek			index = next_index;
159ce39a800ea87c655de49af021c8b20ee323cb40dAndy Gospodarek		}
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tlb_init_slave(slave);
163f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarov}
1645af47b2ff124fdad9ba84baeb9f7eeebeb227b43Jay Vosburgh
165f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarov/* Caller must hold bond lock for read */
166f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarovstatic void tlb_clear_slave(struct bonding *bond, struct slave *slave,
167f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarov			 int save_load)
168f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarov{
169f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarov	_lock_tx_hashtbl_bh(bond);
170f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarov	__tlb_clear_slave(bond, slave, save_load);
171f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarov	_unlock_tx_hashtbl_bh(bond);
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Must be called before starting the monitor timer */
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tlb_initialize(struct bonding *bond)
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int size = TLB_HASH_TABLE_SIZE * sizeof(struct tlb_client_info);
1790d206a3af4329bd833cfa5fe1cc7fe146e49c131Mitch Williams	struct tlb_client_info *new_hashtbl;
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
182243cb4e56061c3f4cb76312c5527840344d57c3bJoe Jin	new_hashtbl = kzalloc(size, GFP_KERNEL);
183e404decb0fb017be80552adee894b35307b6c7b4Joe Perches	if (!new_hashtbl)
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -1;
185e404decb0fb017be80552adee894b35307b6c7b4Joe Perches
186f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarov	_lock_tx_hashtbl_bh(bond);
1870d206a3af4329bd833cfa5fe1cc7fe146e49c131Mitch Williams
1880d206a3af4329bd833cfa5fe1cc7fe146e49c131Mitch Williams	bond_info->tx_hashtbl = new_hashtbl;
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < TLB_HASH_TABLE_SIZE; i++) {
19138dbaf0afb518e462de7afca552acad048237a73Peter Pan(潘卫平)		tlb_init_table_entry(&bond_info->tx_hashtbl[i], 0);
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
194f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarov	_unlock_tx_hashtbl_bh(bond);
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Must be called only after all slaves have been released */
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void tlb_deinitialize(struct bonding *bond)
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
204f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarov	_lock_tx_hashtbl_bh(bond);
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(bond_info->tx_hashtbl);
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bond_info->tx_hashtbl = NULL;
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
209f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarov	_unlock_tx_hashtbl_bh(bond);
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
212097811bb48c7837db94d7fe5d94f0f4b5e19e78cJiri Pirkostatic long long compute_gap(struct slave *slave)
213097811bb48c7837db94d7fe5d94f0f4b5e19e78cJiri Pirko{
214097811bb48c7837db94d7fe5d94f0f4b5e19e78cJiri Pirko	return (s64) (slave->speed << 20) - /* Convert to Megabit per sec */
215097811bb48c7837db94d7fe5d94f0f4b5e19e78cJiri Pirko	       (s64) (SLAVE_TLB_INFO(slave).load << 3); /* Bytes to bits */
216097811bb48c7837db94d7fe5d94f0f4b5e19e78cJiri Pirko}
217097811bb48c7837db94d7fe5d94f0f4b5e19e78cJiri Pirko
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Caller must hold bond lock for read */
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct slave *tlb_get_least_loaded_slave(struct bonding *bond)
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct slave *slave, *least_loaded;
222097811bb48c7837db94d7fe5d94f0f4b5e19e78cJiri Pirko	long long max_gap;
223097811bb48c7837db94d7fe5d94f0f4b5e19e78cJiri Pirko	int i;
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
225097811bb48c7837db94d7fe5d94f0f4b5e19e78cJiri Pirko	least_loaded = NULL;
226097811bb48c7837db94d7fe5d94f0f4b5e19e78cJiri Pirko	max_gap = LLONG_MIN;
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Find the slave with the largest gap */
229097811bb48c7837db94d7fe5d94f0f4b5e19e78cJiri Pirko	bond_for_each_slave(bond, slave, i) {
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (SLAVE_IS_OK(slave)) {
231097811bb48c7837db94d7fe5d94f0f4b5e19e78cJiri Pirko			long long gap = compute_gap(slave);
232097811bb48c7837db94d7fe5d94f0f4b5e19e78cJiri Pirko
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (max_gap < gap) {
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				least_loaded = slave;
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				max_gap = gap;
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return least_loaded;
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
243f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarovstatic struct slave *__tlb_choose_channel(struct bonding *bond, u32 hash_index,
244f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarov						u32 skb_len)
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tlb_client_info *hash_table;
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct slave *assigned_slave;
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hash_table = bond_info->tx_hashtbl;
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	assigned_slave = hash_table[hash_index].tx_slave;
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!assigned_slave) {
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		assigned_slave = tlb_get_least_loaded_slave(bond);
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (assigned_slave) {
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			struct tlb_slave_info *slave_info =
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				&(SLAVE_TLB_INFO(assigned_slave));
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			u32 next_index = slave_info->head;
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			hash_table[hash_index].tx_slave = assigned_slave;
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			hash_table[hash_index].next = next_index;
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			hash_table[hash_index].prev = TLB_NULL_INDEX;
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (next_index != TLB_NULL_INDEX) {
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				hash_table[next_index].prev = hash_index;
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			slave_info->head = hash_index;
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			slave_info->load +=
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				hash_table[hash_index].load_history;
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (assigned_slave) {
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		hash_table[hash_index].tx_bytes += skb_len;
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return assigned_slave;
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
281f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarov/* Caller must hold bond lock for read */
282f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarovstatic struct slave *tlb_choose_channel(struct bonding *bond, u32 hash_index,
283f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarov					u32 skb_len)
284f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarov{
285f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarov	struct slave *tx_slave;
286f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarov	/*
287f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarov	 * We don't need to disable softirq here, becase
288f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarov	 * tlb_choose_channel() is only called by bond_alb_xmit()
289f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarov	 * which already has softirq disabled.
290f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarov	 */
291f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarov	_lock_tx_hashtbl(bond);
292f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarov	tx_slave = __tlb_choose_channel(bond, hash_index, skb_len);
293f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarov	_unlock_tx_hashtbl(bond);
294f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarov	return tx_slave;
295f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarov}
296f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarov
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*********************** rlb specific functions ***************************/
298f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarovstatic inline void _lock_rx_hashtbl_bh(struct bonding *bond)
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3006603a6f25e4bca922a7dfbf0bf03072d98850176Jay Vosburgh	spin_lock_bh(&(BOND_ALB_INFO(bond).rx_hashtbl_lock));
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
303f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarovstatic inline void _unlock_rx_hashtbl_bh(struct bonding *bond)
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3056603a6f25e4bca922a7dfbf0bf03072d98850176Jay Vosburgh	spin_unlock_bh(&(BOND_ALB_INFO(bond).rx_hashtbl_lock));
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
308f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarovstatic inline void _lock_rx_hashtbl(struct bonding *bond)
309f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarov{
310f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarov	spin_lock(&(BOND_ALB_INFO(bond).rx_hashtbl_lock));
311f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarov}
312f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarov
313f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarovstatic inline void _unlock_rx_hashtbl(struct bonding *bond)
314f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarov{
315f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarov	spin_unlock(&(BOND_ALB_INFO(bond).rx_hashtbl_lock));
316f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarov}
317f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarov
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* when an ARP REPLY is received from a client update its info
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * in the rx_hashtbl
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rlb_update_entry_from_arp(struct bonding *bond, struct arp_pkt *arp)
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct rlb_client_info *client_info;
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 hash_index;
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
327f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarov	_lock_rx_hashtbl_bh(bond);
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hash_index = _simple_hash((u8*)&(arp->ip_src), sizeof(arp->ip_src));
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	client_info = &(bond_info->rx_hashtbl[hash_index]);
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((client_info->assigned) &&
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    (client_info->ip_src == arp->ip_dst) &&
33442d782ac1bef7cbcdf05b857731345c6e8149f90Flavio Leitner	    (client_info->ip_dst == arp->ip_src) &&
33542d782ac1bef7cbcdf05b857731345c6e8149f90Flavio Leitner	    (compare_ether_addr_64bits(client_info->mac_dst, arp->mac_src))) {
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* update the clients MAC address */
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memcpy(client_info->mac_dst, arp->mac_src, ETH_ALEN);
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		client_info->ntt = 1;
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bond_info->rx_ntt = 1;
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
342f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarov	_unlock_rx_hashtbl_bh(bond);
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
345b99215cdc6e191f5649687536d4fb0faa3d7f56eDavid S. Millerstatic int rlb_arp_recv(struct sk_buff *skb, struct bonding *bond,
3463aba891dde3842d89ad022237b99c1ed308040b0Jiri Pirko			 struct slave *slave)
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3483aba891dde3842d89ad022237b99c1ed308040b0Jiri Pirko	struct arp_pkt *arp;
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3503aba891dde3842d89ad022237b99c1ed308040b0Jiri Pirko	if (skb->protocol != cpu_to_be16(ETH_P_ARP))
351b99215cdc6e191f5649687536d4fb0faa3d7f56eDavid S. Miller		goto out;
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3533aba891dde3842d89ad022237b99c1ed308040b0Jiri Pirko	arp = (struct arp_pkt *) skb->data;
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!arp) {
3555a03cdb7f2d7ff88e50153d8c3b90a1d52dca435Holger Eitzenberger		pr_debug("Packet has no ARP data\n");
356b99215cdc6e191f5649687536d4fb0faa3d7f56eDavid S. Miller		goto out;
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3593aba891dde3842d89ad022237b99c1ed308040b0Jiri Pirko	if (!pskb_may_pull(skb, arp_hdr_len(bond->dev)))
360b99215cdc6e191f5649687536d4fb0faa3d7f56eDavid S. Miller		goto out;
361ab12811c89e88f2e66746790b1fe4469ccb7bdd9Andy Gospodarek
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (skb->len < sizeof(struct arp_pkt)) {
3635a03cdb7f2d7ff88e50153d8c3b90a1d52dca435Holger Eitzenberger		pr_debug("Packet is too small to be an ARP\n");
364b99215cdc6e191f5649687536d4fb0faa3d7f56eDavid S. Miller		goto out;
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (arp->op_code == htons(ARPOP_REPLY)) {
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* update rx hash table for this ARP */
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rlb_update_entry_from_arp(bond, arp);
3705a03cdb7f2d7ff88e50153d8c3b90a1d52dca435Holger Eitzenberger		pr_debug("Server received an ARP Reply from client\n");
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
372b99215cdc6e191f5649687536d4fb0faa3d7f56eDavid S. Millerout:
373b99215cdc6e191f5649687536d4fb0faa3d7f56eDavid S. Miller	return RX_HANDLER_ANOTHER;
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Caller must hold bond lock for read */
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct slave *rlb_next_rx_slave(struct bonding *bond)
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct slave *rx_slave, *slave, *start_at;
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i = 0;
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (bond_info->next_rx_slave) {
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		start_at = bond_info->next_rx_slave;
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		start_at = bond->first_slave;
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rx_slave = NULL;
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bond_for_each_slave_from(bond, slave, i, start_at) {
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (SLAVE_IS_OK(slave)) {
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!rx_slave) {
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				rx_slave = slave;
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else if (slave->speed > rx_slave->speed) {
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				rx_slave = slave;
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rx_slave) {
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bond_info->next_rx_slave = rx_slave->next;
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return rx_slave;
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* teach the switch the mac of a disabled slave
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * on the primary for fault tolerance
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Caller must hold bond->curr_slave_lock for write or bond lock for write
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rlb_teach_disabled_mac_on_primary(struct bonding *bond, u8 addr[])
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!bond->curr_active_slave) {
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!bond->alb_info.primary_is_promisc) {
4207e1a1ac1fbaa88fe254400b7f30b775502932ad3Wang Chen		if (!dev_set_promiscuity(bond->curr_active_slave->dev, 1))
4217e1a1ac1fbaa88fe254400b7f30b775502932ad3Wang Chen			bond->alb_info.primary_is_promisc = 1;
4227e1a1ac1fbaa88fe254400b7f30b775502932ad3Wang Chen		else
4237e1a1ac1fbaa88fe254400b7f30b775502932ad3Wang Chen			bond->alb_info.primary_is_promisc = 0;
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bond->alb_info.rlb_promisc_timeout_counter = 0;
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	alb_send_learning_packets(bond->curr_active_slave, addr);
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* slave being removed should not be active at this point
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Caller must hold bond lock for read
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rlb_clear_slave(struct bonding *bond, struct slave *slave)
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct rlb_client_info *rx_hash_table;
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 index, next_index;
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* clear slave from rx_hashtbl */
442f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarov	_lock_rx_hashtbl_bh(bond);
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rx_hash_table = bond_info->rx_hashtbl;
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	index = bond_info->rx_hashtbl_head;
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (; index != RLB_NULL_INDEX; index = next_index) {
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		next_index = rx_hash_table[index].next;
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (rx_hash_table[index].slave == slave) {
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			struct slave *assigned_slave = rlb_next_rx_slave(bond);
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (assigned_slave) {
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				rx_hash_table[index].slave = assigned_slave;
453885a136c52a8871175477baf3903e1c38751b35aEric Dumazet				if (compare_ether_addr_64bits(rx_hash_table[index].mac_dst,
454885a136c52a8871175477baf3903e1c38751b35aEric Dumazet							      mac_bcast)) {
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					bond_info->rx_hashtbl[index].ntt = 1;
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					bond_info->rx_ntt = 1;
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					/* A slave has been removed from the
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 * table because it is either disabled
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 * or being released. We must retry the
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 * update to avoid clients from not
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 * being updated & disconnecting when
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 * there is stress
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 */
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					bond_info->rlb_update_retry_counter =
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						RLB_UPDATE_RETRY;
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {  /* there is no active slave */
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				rx_hash_table[index].slave = NULL;
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
473f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarov	_unlock_rx_hashtbl_bh(bond);
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4756603a6f25e4bca922a7dfbf0bf03072d98850176Jay Vosburgh	write_lock_bh(&bond->curr_slave_lock);
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (slave != bond->curr_active_slave) {
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rlb_teach_disabled_mac_on_primary(bond, slave->dev->dev_addr);
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4816603a6f25e4bca922a7dfbf0bf03072d98850176Jay Vosburgh	write_unlock_bh(&bond->curr_slave_lock);
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rlb_update_client(struct rlb_client_info *client_info)
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!client_info->slave) {
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < RLB_ARP_BURST_SIZE; i++) {
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct sk_buff *skb;
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		skb = arp_create(ARPOP_REPLY, ETH_P_ARP,
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 client_info->ip_dst,
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 client_info->slave->dev,
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 client_info->ip_src,
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 client_info->mac_dst,
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 client_info->slave->dev->dev_addr,
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 client_info->mac_dst);
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!skb) {
503a4aee5c808fc5bf6889c9012217841eb3fd91a6aJoe Perches			pr_err("%s: Error: failed to create an ARP packet\n",
5044e0952c74ee450ded86e8946ce58ea8dfd05b007Mitch Williams			       client_info->slave->dev->master->name);
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		skb->dev = client_info->slave->dev;
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (client_info->tag) {
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			skb = vlan_put_tag(skb, client_info->vlan_id);
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!skb) {
513a4aee5c808fc5bf6889c9012217841eb3fd91a6aJoe Perches				pr_err("%s: Error: failed to insert VLAN tag\n",
5144e0952c74ee450ded86e8946ce58ea8dfd05b007Mitch Williams				       client_info->slave->dev->master->name);
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				continue;
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		arp_xmit(skb);
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* sends ARP REPLIES that update the clients that need updating */
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rlb_update_rx_clients(struct bonding *bond)
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct rlb_client_info *client_info;
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 hash_index;
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
530f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarov	_lock_rx_hashtbl_bh(bond);
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hash_index = bond_info->rx_hashtbl_head;
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (; hash_index != RLB_NULL_INDEX; hash_index = client_info->next) {
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		client_info = &(bond_info->rx_hashtbl[hash_index]);
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (client_info->ntt) {
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rlb_update_client(client_info);
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (bond_info->rlb_update_retry_counter == 0) {
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				client_info->ntt = 0;
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
54394e2bd688820aed72b4f8092f88c2ccf64e003deThadeu Lima de Souza Cascardo	/* do not update the entries again until this counter is zero so that
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * not to confuse the clients.
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bond_info->rlb_update_delay_counter = RLB_UPDATE_DELAY;
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
548f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarov	_unlock_rx_hashtbl_bh(bond);
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The slave was assigned a new mac address - update the clients */
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rlb_req_update_slave_clients(struct bonding *bond, struct slave *slave)
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct rlb_client_info *client_info;
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ntt = 0;
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 hash_index;
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
559f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarov	_lock_rx_hashtbl_bh(bond);
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hash_index = bond_info->rx_hashtbl_head;
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (; hash_index != RLB_NULL_INDEX; hash_index = client_info->next) {
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		client_info = &(bond_info->rx_hashtbl[hash_index]);
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((client_info->slave == slave) &&
566885a136c52a8871175477baf3903e1c38751b35aEric Dumazet		    compare_ether_addr_64bits(client_info->mac_dst, mac_bcast)) {
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			client_info->ntt = 1;
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ntt = 1;
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// update the team's flag only after the whole iteration
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ntt) {
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bond_info->rx_ntt = 1;
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		//fasten the change
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bond_info->rlb_update_retry_counter = RLB_UPDATE_RETRY;
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
579f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarov	_unlock_rx_hashtbl_bh(bond);
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* mark all clients using src_ip to be updated */
583d3bb52b0948cf118131c951c5a34a2d4d0246171Al Virostatic void rlb_req_update_subnet_clients(struct bonding *bond, __be32 src_ip)
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct rlb_client_info *client_info;
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 hash_index;
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	_lock_rx_hashtbl(bond);
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hash_index = bond_info->rx_hashtbl_head;
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (; hash_index != RLB_NULL_INDEX; hash_index = client_info->next) {
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		client_info = &(bond_info->rx_hashtbl[hash_index]);
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!client_info->slave) {
596a4aee5c808fc5bf6889c9012217841eb3fd91a6aJoe Perches			pr_err("%s: Error: found a client with no channel in the client's hash table\n",
5974e0952c74ee450ded86e8946ce58ea8dfd05b007Mitch Williams			       bond->dev->name);
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*update all clients using this src_ip, that are not assigned
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * to the team's address (curr_active_slave) and have a known
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * unicast mac address.
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((client_info->ip_src == src_ip) &&
605885a136c52a8871175477baf3903e1c38751b35aEric Dumazet		    compare_ether_addr_64bits(client_info->slave->dev->dev_addr,
606885a136c52a8871175477baf3903e1c38751b35aEric Dumazet			   bond->dev->dev_addr) &&
607885a136c52a8871175477baf3903e1c38751b35aEric Dumazet		    compare_ether_addr_64bits(client_info->mac_dst, mac_bcast)) {
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			client_info->ntt = 1;
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bond_info->rx_ntt = 1;
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	_unlock_rx_hashtbl(bond);
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Caller must hold both bond and ptr locks for read */
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct slave *rlb_choose_channel(struct sk_buff *skb, struct bonding *bond)
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
620a16aeb36239ce612699ed64a75a03c88cbc657e8Arnaldo Carvalho de Melo	struct arp_pkt *arp = arp_pkt(skb);
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct slave *assigned_slave;
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct rlb_client_info *client_info;
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 hash_index = 0;
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	_lock_rx_hashtbl(bond);
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
627e364a3416d81c7717dd642dc9b3ab132b7885f66Amerigo Wang	hash_index = _simple_hash((u8 *)&arp->ip_dst, sizeof(arp->ip_dst));
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	client_info = &(bond_info->rx_hashtbl[hash_index]);
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (client_info->assigned) {
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((client_info->ip_src == arp->ip_src) &&
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    (client_info->ip_dst == arp->ip_dst)) {
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* the entry is already assigned to this client */
634885a136c52a8871175477baf3903e1c38751b35aEric Dumazet			if (compare_ether_addr_64bits(arp->mac_dst, mac_bcast)) {
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* update mac address from arp */
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				memcpy(client_info->mac_dst, arp->mac_dst, ETH_ALEN);
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			assigned_slave = client_info->slave;
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (assigned_slave) {
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				_unlock_rx_hashtbl(bond);
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return assigned_slave;
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* the entry is already assigned to some other client,
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * move the old client to primary (curr_active_slave) so
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * that the new client can be assigned to this entry.
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (bond->curr_active_slave &&
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    client_info->slave != bond->curr_active_slave) {
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				client_info->slave = bond->curr_active_slave;
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				rlb_update_client(client_info);
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* assign a new slave */
6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	assigned_slave = rlb_next_rx_slave(bond);
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (assigned_slave) {
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		client_info->ip_src = arp->ip_src;
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		client_info->ip_dst = arp->ip_dst;
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* arp->mac_dst is broadcast for arp reqeusts.
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * will be updated with clients actual unicast mac address
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * upon receiving an arp reply.
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memcpy(client_info->mac_dst, arp->mac_dst, ETH_ALEN);
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		client_info->slave = assigned_slave;
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
669885a136c52a8871175477baf3903e1c38751b35aEric Dumazet		if (compare_ether_addr_64bits(client_info->mac_dst, mac_bcast)) {
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			client_info->ntt = 1;
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bond->alb_info.rx_ntt = 1;
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			client_info->ntt = 0;
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
676cc0e40700656b09d93b062ef6c818aa45429d09aJiri Pirko		if (bond_vlan_used(bond)) {
677966bc6f434df4a02108d01dda8cd52951fe853daJay Vosburgh			if (!vlan_get_tag(skb, &client_info->vlan_id))
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				client_info->tag = 1;
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!client_info->assigned) {
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			u32 prev_tbl_head = bond_info->rx_hashtbl_head;
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bond_info->rx_hashtbl_head = hash_index;
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			client_info->next = prev_tbl_head;
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (prev_tbl_head != RLB_NULL_INDEX) {
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				bond_info->rx_hashtbl[prev_tbl_head].prev =
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					hash_index;
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			client_info->assigned = 1;
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	_unlock_rx_hashtbl(bond);
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return assigned_slave;
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* chooses (and returns) transmit channel for arp reply
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * does not choose channel for other arp types since they are
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * sent on the curr_active_slave
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct slave *rlb_arp_xmit(struct sk_buff *skb, struct bonding *bond)
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
704a16aeb36239ce612699ed64a75a03c88cbc657e8Arnaldo Carvalho de Melo	struct arp_pkt *arp = arp_pkt(skb);
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct slave *tx_slave = NULL;
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
707f14c4e4e3651b76ae09082fa66cda37e10ac2b43Brian Haley	if (arp->op_code == htons(ARPOP_REPLY)) {
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* the arp must be sent on the selected
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		* rx channel
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*/
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tx_slave = rlb_choose_channel(skb, bond);
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (tx_slave) {
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			memcpy(arp->mac_src,tx_slave->dev->dev_addr, ETH_ALEN);
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
7155a03cdb7f2d7ff88e50153d8c3b90a1d52dca435Holger Eitzenberger		pr_debug("Server sent ARP Reply packet\n");
716f14c4e4e3651b76ae09082fa66cda37e10ac2b43Brian Haley	} else if (arp->op_code == htons(ARPOP_REQUEST)) {
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Create an entry in the rx_hashtbl for this client as a
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * place holder.
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * When the arp reply is received the entry will be updated
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * with the correct unicast address of the client.
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rlb_choose_channel(skb, bond);
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
72477c8e2c01542649f7a02fef8eb3b3d0e7fed6bbdPeter Pan(潘卫平)		/* The ARP reply packets must be delayed so that
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * they can cancel out the influence of the ARP request.
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bond->alb_info.rlb_update_delay_counter = RLB_UPDATE_DELAY;
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* arp requests are broadcast and are sent on the primary
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * the arp request will collapse all clients on the subnet to
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * the primary slave. We must register these clients to be
7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * updated with their assigned mac.
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rlb_req_update_subnet_clients(bond, arp->ip_src);
7355a03cdb7f2d7ff88e50153d8c3b90a1d52dca435Holger Eitzenberger		pr_debug("Server sent ARP Request packet\n");
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return tx_slave;
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Caller must hold bond lock for read */
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rlb_rebalance(struct bonding *bond)
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct slave *assigned_slave;
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct rlb_client_info *client_info;
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ntt;
7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 hash_index;
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
750f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarov	_lock_rx_hashtbl_bh(bond);
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ntt = 0;
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hash_index = bond_info->rx_hashtbl_head;
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (; hash_index != RLB_NULL_INDEX; hash_index = client_info->next) {
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		client_info = &(bond_info->rx_hashtbl[hash_index]);
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		assigned_slave = rlb_next_rx_slave(bond);
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (assigned_slave && (client_info->slave != assigned_slave)) {
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			client_info->slave = assigned_slave;
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			client_info->ntt = 1;
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ntt = 1;
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* update the team's flag only after the whole iteration */
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ntt) {
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bond_info->rx_ntt = 1;
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
768f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarov	_unlock_rx_hashtbl_bh(bond);
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Caller must hold rx_hashtbl lock */
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rlb_init_table_entry(struct rlb_client_info *entry)
7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(entry, 0, sizeof(struct rlb_client_info));
7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	entry->next = RLB_NULL_INDEX;
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	entry->prev = RLB_NULL_INDEX;
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int rlb_initialize(struct bonding *bond)
7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
7820d206a3af4329bd833cfa5fe1cc7fe146e49c131Mitch Williams	struct rlb_client_info	*new_hashtbl;
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int size = RLB_HASH_TABLE_SIZE * sizeof(struct rlb_client_info);
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7860d206a3af4329bd833cfa5fe1cc7fe146e49c131Mitch Williams	new_hashtbl = kmalloc(size, GFP_KERNEL);
787e404decb0fb017be80552adee894b35307b6c7b4Joe Perches	if (!new_hashtbl)
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -1;
789e404decb0fb017be80552adee894b35307b6c7b4Joe Perches
790f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarov	_lock_rx_hashtbl_bh(bond);
7910d206a3af4329bd833cfa5fe1cc7fe146e49c131Mitch Williams
7920d206a3af4329bd833cfa5fe1cc7fe146e49c131Mitch Williams	bond_info->rx_hashtbl = new_hashtbl;
7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bond_info->rx_hashtbl_head = RLB_NULL_INDEX;
7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < RLB_HASH_TABLE_SIZE; i++) {
7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rlb_init_table_entry(bond_info->rx_hashtbl + i);
7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
800f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarov	_unlock_rx_hashtbl_bh(bond);
8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* register to receive ARPs */
8033aba891dde3842d89ad022237b99c1ed308040b0Jiri Pirko	bond->recv_probe = rlb_arp_recv;
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rlb_deinitialize(struct bonding *bond)
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
812f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarov	_lock_rx_hashtbl_bh(bond);
8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(bond_info->rx_hashtbl);
8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bond_info->rx_hashtbl = NULL;
8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bond_info->rx_hashtbl_head = RLB_NULL_INDEX;
8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
818f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarov	_unlock_rx_hashtbl_bh(bond);
8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rlb_clear_vlan(struct bonding *bond, unsigned short vlan_id)
8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 curr_index;
8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
826f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarov	_lock_rx_hashtbl_bh(bond);
8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	curr_index = bond_info->rx_hashtbl_head;
8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (curr_index != RLB_NULL_INDEX) {
8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct rlb_client_info *curr = &(bond_info->rx_hashtbl[curr_index]);
8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u32 next_index = bond_info->rx_hashtbl[curr_index].next;
8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u32 prev_index = bond_info->rx_hashtbl[curr_index].prev;
8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (curr->tag && (curr->vlan_id == vlan_id)) {
8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (curr_index == bond_info->rx_hashtbl_head) {
8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				bond_info->rx_hashtbl_head = next_index;
8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (prev_index != RLB_NULL_INDEX) {
8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				bond_info->rx_hashtbl[prev_index].next = next_index;
8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (next_index != RLB_NULL_INDEX) {
8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				bond_info->rx_hashtbl[next_index].prev = prev_index;
8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rlb_init_table_entry(curr);
8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		curr_index = next_index;
8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
851f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarov	_unlock_rx_hashtbl_bh(bond);
8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*********************** tlb/rlb shared functions *********************/
8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void alb_send_learning_packets(struct slave *slave, u8 mac_addr[])
8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct bonding *bond = bond_get_bond_by_slave(slave);
8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct learning_pkt pkt;
8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int size = sizeof(struct learning_pkt);
8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(&pkt, 0, size);
8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memcpy(pkt.mac_dst, mac_addr, ETH_ALEN);
8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memcpy(pkt.mac_src, mac_addr, ETH_ALEN);
86609640e6365c679b5642b1c41b6d7078f51689ddfHarvey Harrison	pkt.type = cpu_to_be16(ETH_P_LOOP);
8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < MAX_LP_BURST; i++) {
8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct sk_buff *skb;
8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		char *data;
8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		skb = dev_alloc_skb(size);
8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!skb) {
8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return;
8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data = skb_put(skb, size);
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memcpy(data, &pkt, size);
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
880459a98ed881802dee55897441bc7f77af614368eArnaldo Carvalho de Melo		skb_reset_mac_header(skb);
881b0e380b1d8a8e0aca215df97702f99815f05c094Arnaldo Carvalho de Melo		skb->network_header = skb->mac_header + ETH_HLEN;
8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		skb->protocol = pkt.type;
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		skb->priority = TC_PRIO_CONTROL;
8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		skb->dev = slave->dev;
8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
886cc0e40700656b09d93b062ef6c818aa45429d09aJiri Pirko		if (bond_vlan_used(bond)) {
8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			struct vlan_entry *vlan;
8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			vlan = bond_next_vlan(bond,
8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					      bond->alb_info.current_alb_vlan);
8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bond->alb_info.current_alb_vlan = vlan;
8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!vlan) {
8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				kfree_skb(skb);
8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				continue;
8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			skb = vlan_put_tag(skb, vlan->vlan_id);
8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!skb) {
900a4aee5c808fc5bf6889c9012217841eb3fd91a6aJoe Perches				pr_err("%s: Error: failed to insert VLAN tag\n",
9014e0952c74ee450ded86e8946ce58ea8dfd05b007Mitch Williams				       bond->dev->name);
9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				continue;
9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_queue_xmit(skb);
9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
910b924551bed09f61b64f21bffe241afc5526b091aJiri Bohacstatic int alb_set_slave_mac_addr(struct slave *slave, u8 addr[])
9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev = slave->dev;
9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sockaddr s_addr;
9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
915b924551bed09f61b64f21bffe241afc5526b091aJiri Bohac	if (slave->bond->params.mode == BOND_MODE_TLB) {
9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memcpy(dev->dev_addr, addr, dev->addr_len);
9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* for rlb each slave must have a unique hw mac addresses so that */
9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* each slave will receive packets destined to a different mac */
9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memcpy(s_addr.sa_data, addr, dev->addr_len);
9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	s_addr.sa_family = dev->type;
9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dev_set_mac_address(dev, &s_addr)) {
925a4aee5c808fc5bf6889c9012217841eb3fd91a6aJoe Perches		pr_err("%s: Error: dev_set_mac_address of dev %s failed!\n"
926a4aee5c808fc5bf6889c9012217841eb3fd91a6aJoe Perches		       "ALB mode requires that the base driver support setting the hw address also when the network device's interface is open\n",
9274e0952c74ee450ded86e8946ce58ea8dfd05b007Mitch Williams		       dev->master->name, dev->name);
9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EOPNOTSUPP;
9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
933059fe7a578fba5bbb0fdc0365bfcf6218fa25eb0Jay Vosburgh/*
934059fe7a578fba5bbb0fdc0365bfcf6218fa25eb0Jay Vosburgh * Swap MAC addresses between two slaves.
935059fe7a578fba5bbb0fdc0365bfcf6218fa25eb0Jay Vosburgh *
936059fe7a578fba5bbb0fdc0365bfcf6218fa25eb0Jay Vosburgh * Called with RTNL held, and no other locks.
937059fe7a578fba5bbb0fdc0365bfcf6218fa25eb0Jay Vosburgh *
938059fe7a578fba5bbb0fdc0365bfcf6218fa25eb0Jay Vosburgh */
939059fe7a578fba5bbb0fdc0365bfcf6218fa25eb0Jay Vosburgh
9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void alb_swap_mac_addr(struct bonding *bond, struct slave *slave1, struct slave *slave2)
9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 tmp_mac_addr[ETH_ALEN];
9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memcpy(tmp_mac_addr, slave1->dev->dev_addr, ETH_ALEN);
945b924551bed09f61b64f21bffe241afc5526b091aJiri Bohac	alb_set_slave_mac_addr(slave1, slave2->dev->dev_addr);
946b924551bed09f61b64f21bffe241afc5526b091aJiri Bohac	alb_set_slave_mac_addr(slave2, tmp_mac_addr);
9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
948059fe7a578fba5bbb0fdc0365bfcf6218fa25eb0Jay Vosburgh}
949059fe7a578fba5bbb0fdc0365bfcf6218fa25eb0Jay Vosburgh
950059fe7a578fba5bbb0fdc0365bfcf6218fa25eb0Jay Vosburgh/*
951059fe7a578fba5bbb0fdc0365bfcf6218fa25eb0Jay Vosburgh * Send learning packets after MAC address swap.
952059fe7a578fba5bbb0fdc0365bfcf6218fa25eb0Jay Vosburgh *
9532543331d367c9fe54f4ba73300894bc21e0a08f4Jay Vosburgh * Called with RTNL and no other locks
954059fe7a578fba5bbb0fdc0365bfcf6218fa25eb0Jay Vosburgh */
955059fe7a578fba5bbb0fdc0365bfcf6218fa25eb0Jay Vosburghstatic void alb_fasten_mac_swap(struct bonding *bond, struct slave *slave1,
956059fe7a578fba5bbb0fdc0365bfcf6218fa25eb0Jay Vosburgh				struct slave *slave2)
957059fe7a578fba5bbb0fdc0365bfcf6218fa25eb0Jay Vosburgh{
958059fe7a578fba5bbb0fdc0365bfcf6218fa25eb0Jay Vosburgh	int slaves_state_differ = (SLAVE_IS_OK(slave1) != SLAVE_IS_OK(slave2));
959059fe7a578fba5bbb0fdc0365bfcf6218fa25eb0Jay Vosburgh	struct slave *disabled_slave = NULL;
960059fe7a578fba5bbb0fdc0365bfcf6218fa25eb0Jay Vosburgh
9612543331d367c9fe54f4ba73300894bc21e0a08f4Jay Vosburgh	ASSERT_RTNL();
9622543331d367c9fe54f4ba73300894bc21e0a08f4Jay Vosburgh
9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* fasten the change in the switch */
9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (SLAVE_IS_OK(slave1)) {
9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		alb_send_learning_packets(slave1, slave1->dev->dev_addr);
9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (bond->alb_info.rlb_enabled) {
9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* inform the clients that the mac address
9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * has changed
9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rlb_req_update_slave_clients(bond, slave1);
9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		disabled_slave = slave1;
9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (SLAVE_IS_OK(slave2)) {
9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		alb_send_learning_packets(slave2, slave2->dev->dev_addr);
9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (bond->alb_info.rlb_enabled) {
9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* inform the clients that the mac address
9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * has changed
9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rlb_req_update_slave_clients(bond, slave2);
9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		disabled_slave = slave2;
9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (bond->alb_info.rlb_enabled && slaves_state_differ) {
9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* A disabled slave was assigned an active mac addr */
9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rlb_teach_disabled_mac_on_primary(bond,
9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						  disabled_slave->dev->dev_addr);
9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * alb_change_hw_addr_on_detach
9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @bond: bonding we're working on
9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @slave: the slave that was just detached
9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We assume that @slave was already detached from the slave list.
10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If @slave's permanent hw address is different both from its current
10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * address and from @bond's address, then somewhere in the bond there's
10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a slave that has @slave's permanet address as its current address.
10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We'll make sure that that slave no longer uses @slave's permanent address.
10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
10072543331d367c9fe54f4ba73300894bc21e0a08f4Jay Vosburgh * Caller must hold RTNL and no other locks
10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void alb_change_hw_addr_on_detach(struct bonding *bond, struct slave *slave)
10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int perm_curr_diff;
10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int perm_bond_diff;
10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1014885a136c52a8871175477baf3903e1c38751b35aEric Dumazet	perm_curr_diff = compare_ether_addr_64bits(slave->perm_hwaddr,
1015885a136c52a8871175477baf3903e1c38751b35aEric Dumazet						   slave->dev->dev_addr);
1016885a136c52a8871175477baf3903e1c38751b35aEric Dumazet	perm_bond_diff = compare_ether_addr_64bits(slave->perm_hwaddr,
1017885a136c52a8871175477baf3903e1c38751b35aEric Dumazet						   bond->dev->dev_addr);
10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (perm_curr_diff && perm_bond_diff) {
10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct slave *tmp_slave;
10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int i, found = 0;
10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bond_for_each_slave(bond, tmp_slave, i) {
1024885a136c52a8871175477baf3903e1c38751b35aEric Dumazet			if (!compare_ether_addr_64bits(slave->perm_hwaddr,
1025885a136c52a8871175477baf3903e1c38751b35aEric Dumazet						       tmp_slave->dev->dev_addr)) {
10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				found = 1;
10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (found) {
1032059fe7a578fba5bbb0fdc0365bfcf6218fa25eb0Jay Vosburgh			/* locking: needs RTNL and nothing else */
10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			alb_swap_mac_addr(bond, slave, tmp_slave);
1034059fe7a578fba5bbb0fdc0365bfcf6218fa25eb0Jay Vosburgh			alb_fasten_mac_swap(bond, slave, tmp_slave);
10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * alb_handle_addr_collision_on_attach
10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @bond: bonding we're working on
10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @slave: the slave that was just attached
10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * checks uniqueness of slave's mac address and handles the case the
10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * new slave uses the bonds mac address.
10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If the permanent hw address of @slave is @bond's hw address, we need to
10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * find a different hw address to give @slave, that isn't in use by any other
104977c8e2c01542649f7a02fef8eb3b3d0e7fed6bbdPeter Pan(潘卫平) * slave in the bond. This address must be, of course, one of the permanent
10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * addresses of the other slaves.
10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We go over the slave list, and for each slave there we compare its
10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * permanent hw address with the current address of all the other slaves.
10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If no match was found, then we've found a slave with a permanent address
10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * that isn't used by any other slave in the bond, so we can assign it to
10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @slave.
10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * assumption: this function is called before @slave is attached to the
10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 	       bond slave list.
10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * caller must hold the bond lock for write since the mac addresses are compared
10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and may be swapped.
10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slave *slave)
10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct slave *tmp_slave1, *tmp_slave2, *free_mac_slave;
10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct slave *has_bond_addr = bond->curr_active_slave;
10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i, j, found = 0;
10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (bond->slave_cnt == 0) {
10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* this is the first slave */
10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* if slave's mac address differs from bond's mac address
10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * check uniqueness of slave's mac address against the other
10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * slaves in the bond.
10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
1079885a136c52a8871175477baf3903e1c38751b35aEric Dumazet	if (compare_ether_addr_64bits(slave->perm_hwaddr, bond->dev->dev_addr)) {
10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bond_for_each_slave(bond, tmp_slave1, i) {
1081885a136c52a8871175477baf3903e1c38751b35aEric Dumazet			if (!compare_ether_addr_64bits(tmp_slave1->dev->dev_addr,
1082885a136c52a8871175477baf3903e1c38751b35aEric Dumazet						       slave->dev->dev_addr)) {
10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				found = 1;
10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10886b38aefe924daf2e4fdd73b384f21c913f31b668John W. Linville		if (!found)
10896b38aefe924daf2e4fdd73b384f21c913f31b668John W. Linville			return 0;
10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10916b38aefe924daf2e4fdd73b384f21c913f31b668John W. Linville		/* Try setting slave mac to bond address and fall-through
10926b38aefe924daf2e4fdd73b384f21c913f31b668John W. Linville		   to code handling that situation below... */
1093b924551bed09f61b64f21bffe241afc5526b091aJiri Bohac		alb_set_slave_mac_addr(slave, bond->dev->dev_addr);
10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* The slave's address is equal to the address of the bond.
10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Search for a spare address in the bond for this slave.
10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	free_mac_slave = NULL;
11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bond_for_each_slave(bond, tmp_slave1, i) {
11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		found = 0;
11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bond_for_each_slave(bond, tmp_slave2, j) {
1104885a136c52a8871175477baf3903e1c38751b35aEric Dumazet			if (!compare_ether_addr_64bits(tmp_slave1->perm_hwaddr,
1105885a136c52a8871175477baf3903e1c38751b35aEric Dumazet						       tmp_slave2->dev->dev_addr)) {
11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				found = 1;
11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!found) {
11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* no slave has tmp_slave1's perm addr
11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * as its curr addr
11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			free_mac_slave = tmp_slave1;
11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!has_bond_addr) {
1120885a136c52a8871175477baf3903e1c38751b35aEric Dumazet			if (!compare_ether_addr_64bits(tmp_slave1->dev->dev_addr,
1121885a136c52a8871175477baf3903e1c38751b35aEric Dumazet						       bond->dev->dev_addr)) {
11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				has_bond_addr = tmp_slave1;
11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (free_mac_slave) {
1129b924551bed09f61b64f21bffe241afc5526b091aJiri Bohac		alb_set_slave_mac_addr(slave, free_mac_slave->perm_hwaddr);
11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1131a4aee5c808fc5bf6889c9012217841eb3fd91a6aJoe Perches		pr_warning("%s: Warning: the hw address of slave %s is in use by the bond; giving it the hw address of %s\n",
1132e5e2a8fd8358d1b3a2c51c3248edee72e4194703Jiri Pirko			   bond->dev->name, slave->dev->name,
1133e5e2a8fd8358d1b3a2c51c3248edee72e4194703Jiri Pirko			   free_mac_slave->dev->name);
11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else if (has_bond_addr) {
1136a4aee5c808fc5bf6889c9012217841eb3fd91a6aJoe Perches		pr_err("%s: Error: the hw address of slave %s is in use by the bond; couldn't find a slave with a free hw address to give it (this should not have happened)\n",
11374e0952c74ee450ded86e8946ce58ea8dfd05b007Mitch Williams		       bond->dev->name, slave->dev->name);
11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EFAULT;
11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * alb_set_mac_address
11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @bond:
11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @addr:
11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * In TLB mode all slaves are configured to the bond's hw address, but set
11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * their dev_addr field to different addresses (based on their permanent hw
11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * addresses).
11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * For each slave, this function sets the interface to the new address and then
11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * changes its dev_addr field to its previous value.
11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Unwinding assumes bond's mac address has not yet changed.
11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int alb_set_mac_address(struct bonding *bond, void *addr)
11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sockaddr sa;
11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct slave *slave, *stop_at;
11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char tmp_addr[ETH_ALEN];
11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int res;
11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (bond->alb_info.rlb_enabled) {
11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
11681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bond_for_each_slave(bond, slave, i) {
11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* save net_device's current hw address */
11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memcpy(tmp_addr, slave->dev->dev_addr, ETH_ALEN);
11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		res = dev_set_mac_address(slave->dev, addr);
11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* restore net_device's hw address */
11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memcpy(slave->dev->dev_addr, tmp_addr, ETH_ALEN);
11781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1179eb7cc59a038b4e1914ae991d313f35904924759fStephen Hemminger		if (res)
11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto unwind;
11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
11841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsunwind:
11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memcpy(sa.sa_data, bond->dev->dev_addr, bond->dev->addr_len);
11871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sa.sa_family = bond->dev->type;
11881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* unwind from head to the slave that failed */
11901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	stop_at = slave;
11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bond_for_each_slave_from_to(bond, slave, i, bond->first_slave, stop_at) {
11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memcpy(tmp_addr, slave->dev->dev_addr, ETH_ALEN);
11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_set_mac_address(slave->dev, &sa);
11941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memcpy(slave->dev->dev_addr, tmp_addr, ETH_ALEN);
11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return res;
11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/************************ exported alb funcions ************************/
12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint bond_alb_initialize(struct bonding *bond, int rlb_enabled)
12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int res;
12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	res = tlb_initialize(bond);
12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (res) {
12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return res;
12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rlb_enabled) {
12121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bond->alb_info.rlb_enabled = 1;
12131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* initialize rlb */
12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		res = rlb_initialize(bond);
12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (res) {
12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			tlb_deinitialize(bond);
12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return res;
12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1219b76850ab577bb4b929e60894d2025bbfcc043984Mitch Williams	} else {
1220b76850ab577bb4b929e60894d2025bbfcc043984Mitch Williams		bond->alb_info.rlb_enabled = 0;
12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid bond_alb_deinitialize(struct bonding *bond)
12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
12291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tlb_deinitialize(bond);
12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (bond_info->rlb_enabled) {
12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rlb_deinitialize(bond);
12341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev)
12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1239454d7c9b14e20fd1949e2686e9de4a2926e01476Wang Chen	struct bonding *bond = netdev_priv(bond_dev);
12401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ethhdr *eth_data;
12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct slave *tx_slave = NULL;
1243d3bb52b0948cf118131c951c5a34a2d4d0246171Al Viro	static const __be32 ip_bcast = htonl(0xffffffff);
12441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int hash_size = 0;
12451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int do_tx_balance = 1;
12461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 hash_index = 0;
1247eddc9ec53be2ecdbf4efe0efd4a83052594f0ac0Arnaldo Carvalho de Melo	const u8 *hash_start = NULL;
12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int res = 1;
12492d1ea19da0e84117d3ebbad981e4664bef03152eVlad Yasevich	struct ipv6hdr *ip6hdr;
12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1251459a98ed881802dee55897441bc7f77af614368eArnaldo Carvalho de Melo	skb_reset_mac_header(skb);
12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	eth_data = eth_hdr(skb);
12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12540693e88e6ccf615d9674548d8b924cdd9a1c976cMichał Mirosław	/* make sure that the curr_active_slave do not change during tx
12551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
12561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	read_lock(&bond->curr_slave_lock);
12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (ntohs(skb->protocol)) {
1259eddc9ec53be2ecdbf4efe0efd4a83052594f0ac0Arnaldo Carvalho de Melo	case ETH_P_IP: {
1260eddc9ec53be2ecdbf4efe0efd4a83052594f0ac0Arnaldo Carvalho de Melo		const struct iphdr *iph = ip_hdr(skb);
1261eddc9ec53be2ecdbf4efe0efd4a83052594f0ac0Arnaldo Carvalho de Melo
1262885a136c52a8871175477baf3903e1c38751b35aEric Dumazet		if (!compare_ether_addr_64bits(eth_data->h_dest, mac_bcast) ||
1263eddc9ec53be2ecdbf4efe0efd4a83052594f0ac0Arnaldo Carvalho de Melo		    (iph->daddr == ip_bcast) ||
1264eddc9ec53be2ecdbf4efe0efd4a83052594f0ac0Arnaldo Carvalho de Melo		    (iph->protocol == IPPROTO_IGMP)) {
12651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			do_tx_balance = 0;
12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
12671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1268eddc9ec53be2ecdbf4efe0efd4a83052594f0ac0Arnaldo Carvalho de Melo		hash_start = (char *)&(iph->daddr);
1269eddc9ec53be2ecdbf4efe0efd4a83052594f0ac0Arnaldo Carvalho de Melo		hash_size = sizeof(iph->daddr);
1270eddc9ec53be2ecdbf4efe0efd4a83052594f0ac0Arnaldo Carvalho de Melo	}
12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case ETH_P_IPV6:
12732d1ea19da0e84117d3ebbad981e4664bef03152eVlad Yasevich		/* IPv6 doesn't really use broadcast mac address, but leave
12742d1ea19da0e84117d3ebbad981e4664bef03152eVlad Yasevich		 * that here just in case.
12752d1ea19da0e84117d3ebbad981e4664bef03152eVlad Yasevich		 */
1276885a136c52a8871175477baf3903e1c38751b35aEric Dumazet		if (!compare_ether_addr_64bits(eth_data->h_dest, mac_bcast)) {
12771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			do_tx_balance = 0;
12781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
12792d1ea19da0e84117d3ebbad981e4664bef03152eVlad Yasevich		}
12802d1ea19da0e84117d3ebbad981e4664bef03152eVlad Yasevich
12812d1ea19da0e84117d3ebbad981e4664bef03152eVlad Yasevich		/* IPv6 uses all-nodes multicast as an equivalent to
12822d1ea19da0e84117d3ebbad981e4664bef03152eVlad Yasevich		 * broadcasts in IPv4.
12832d1ea19da0e84117d3ebbad981e4664bef03152eVlad Yasevich		 */
1284885a136c52a8871175477baf3903e1c38751b35aEric Dumazet		if (!compare_ether_addr_64bits(eth_data->h_dest, mac_v6_allmcast)) {
12852d1ea19da0e84117d3ebbad981e4664bef03152eVlad Yasevich			do_tx_balance = 0;
12862d1ea19da0e84117d3ebbad981e4664bef03152eVlad Yasevich			break;
12872d1ea19da0e84117d3ebbad981e4664bef03152eVlad Yasevich		}
12882d1ea19da0e84117d3ebbad981e4664bef03152eVlad Yasevich
12892d1ea19da0e84117d3ebbad981e4664bef03152eVlad Yasevich		/* Additianally, DAD probes should not be tx-balanced as that
12902d1ea19da0e84117d3ebbad981e4664bef03152eVlad Yasevich		 * will lead to false positives for duplicate addresses and
12912d1ea19da0e84117d3ebbad981e4664bef03152eVlad Yasevich		 * prevent address configuration from working.
12922d1ea19da0e84117d3ebbad981e4664bef03152eVlad Yasevich		 */
12932d1ea19da0e84117d3ebbad981e4664bef03152eVlad Yasevich		ip6hdr = ipv6_hdr(skb);
12942d1ea19da0e84117d3ebbad981e4664bef03152eVlad Yasevich		if (ipv6_addr_any(&ip6hdr->saddr)) {
12952d1ea19da0e84117d3ebbad981e4664bef03152eVlad Yasevich			do_tx_balance = 0;
12962d1ea19da0e84117d3ebbad981e4664bef03152eVlad Yasevich			break;
12971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
12981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12990660e03f6b18f19b6bbafe7583265a51b90daf36Arnaldo Carvalho de Melo		hash_start = (char *)&(ipv6_hdr(skb)->daddr);
13000660e03f6b18f19b6bbafe7583265a51b90daf36Arnaldo Carvalho de Melo		hash_size = sizeof(ipv6_hdr(skb)->daddr);
13011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
13021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case ETH_P_IPX:
1303d3bb52b0948cf118131c951c5a34a2d4d0246171Al Viro		if (ipx_hdr(skb)->ipx_checksum != IPX_NO_CHECKSUM) {
13041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* something is wrong with this packet */
13051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			do_tx_balance = 0;
13061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
13071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
13081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ipx_hdr(skb)->ipx_type != IPX_TYPE_NCP) {
13101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* The only protocol worth balancing in
13111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * this family since it has an "ARP" like
13121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * mechanism
13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
13141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			do_tx_balance = 0;
13151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
13161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
13171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		hash_start = (char*)eth_data->h_dest;
13191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		hash_size = ETH_ALEN;
13201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
13211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case ETH_P_ARP:
13221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		do_tx_balance = 0;
13231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (bond_info->rlb_enabled) {
13241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			tx_slave = rlb_arp_xmit(skb, bond);
13251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
13261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
13271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
13281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		do_tx_balance = 0;
13291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
13301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (do_tx_balance) {
13331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		hash_index = _simple_hash(hash_start, hash_size);
13341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tx_slave = tlb_choose_channel(bond, hash_index, skb->len);
13351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!tx_slave) {
13381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* unbalanced or unassigned, send through primary */
13391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tx_slave = bond->curr_active_slave;
13401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bond_info->unbalanced_load += skb->len;
13411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (tx_slave && SLAVE_IS_OK(tx_slave)) {
13441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (tx_slave != bond->curr_active_slave) {
13451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			memcpy(eth_data->h_source,
13461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       tx_slave->dev->dev_addr,
13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       ETH_ALEN);
13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
13491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		res = bond_dev_queue_xmit(bond, skb, tx_slave->dev);
13511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
13521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (tx_slave) {
1353f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarov			_lock_tx_hashtbl(bond);
1354f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarov			__tlb_clear_slave(bond, tx_slave, 0);
1355f515e6b77045b4b1f54617d9fbf4a22b95a58757Maxim Uvarov			_unlock_tx_hashtbl(bond);
13561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
13571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (res) {
13601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* no suitable interface, frame not sent */
13611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_kfree_skb(skb);
13621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	read_unlock(&bond->curr_slave_lock);
13640693e88e6ccf615d9674548d8b924cdd9a1c976cMichał Mirosław
1365ec634fe328182a1a098585bfc7b69e5042bdb08dPatrick McHardy	return NETDEV_TX_OK;
13661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13681b76b31693d4a6088dec104ff6a6ead54081a3c2Jay Vosburghvoid bond_alb_monitor(struct work_struct *work)
13691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
13701b76b31693d4a6088dec104ff6a6ead54081a3c2Jay Vosburgh	struct bonding *bond = container_of(work, struct bonding,
13711b76b31693d4a6088dec104ff6a6ead54081a3c2Jay Vosburgh					    alb_work.work);
13721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
13731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct slave *slave;
13741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	read_lock(&bond->lock);
13771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (bond->slave_cnt == 0) {
13791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bond_info->tx_rebalance_counter = 0;
13801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bond_info->lp_counter = 0;
13811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto re_arm;
13821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bond_info->tx_rebalance_counter++;
13851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bond_info->lp_counter++;
13861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* send learning packets */
13881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (bond_info->lp_counter >= BOND_ALB_LP_TICKS) {
13891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* change of curr_active_slave involves swapping of mac addresses.
13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * in order to avoid this swapping from happening while
13911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * sending the learning packets, the curr_slave_lock must be held for
13921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * read.
13931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
13941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		read_lock(&bond->curr_slave_lock);
13951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bond_for_each_slave(bond, slave, i) {
1397e944ef79184ff7f283e7bf79496d2873a0b0410bMitch Williams			alb_send_learning_packets(slave, slave->dev->dev_addr);
13981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
13991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		read_unlock(&bond->curr_slave_lock);
14011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bond_info->lp_counter = 0;
14031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* rebalance tx traffic */
14061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (bond_info->tx_rebalance_counter >= BOND_TLB_REBALANCE_TICKS) {
14071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		read_lock(&bond->curr_slave_lock);
14091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bond_for_each_slave(bond, slave, i) {
14111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			tlb_clear_slave(bond, slave, 1);
14121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (slave == bond->curr_active_slave) {
14131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				SLAVE_TLB_INFO(slave).load =
14141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					bond_info->unbalanced_load /
14151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						BOND_TLB_REBALANCE_INTERVAL;
14161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				bond_info->unbalanced_load = 0;
14171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
14181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
14191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		read_unlock(&bond->curr_slave_lock);
14211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bond_info->tx_rebalance_counter = 0;
14231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* handle rlb stuff */
14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (bond_info->rlb_enabled) {
14271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (bond_info->primary_is_promisc &&
14281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    (++bond_info->rlb_promisc_timeout_counter >= RLB_PROMISC_TIMEOUT)) {
14291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1430d0e81b7e2246a41d068ecaf15aac9de570816d63Jay Vosburgh			/*
1431d0e81b7e2246a41d068ecaf15aac9de570816d63Jay Vosburgh			 * dev_set_promiscuity requires rtnl and
1432e6d265e8504ab4a3368b8645d318b344ee88b280Jay Vosburgh			 * nothing else.  Avoid race with bond_close.
1433d0e81b7e2246a41d068ecaf15aac9de570816d63Jay Vosburgh			 */
1434d0e81b7e2246a41d068ecaf15aac9de570816d63Jay Vosburgh			read_unlock(&bond->lock);
1435e6d265e8504ab4a3368b8645d318b344ee88b280Jay Vosburgh			if (!rtnl_trylock()) {
1436e6d265e8504ab4a3368b8645d318b344ee88b280Jay Vosburgh				read_lock(&bond->lock);
1437e6d265e8504ab4a3368b8645d318b344ee88b280Jay Vosburgh				goto re_arm;
1438e6d265e8504ab4a3368b8645d318b344ee88b280Jay Vosburgh			}
1439d0e81b7e2246a41d068ecaf15aac9de570816d63Jay Vosburgh
14401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bond_info->rlb_promisc_timeout_counter = 0;
14411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* If the primary was set to promiscuous mode
14431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * because a slave was disabled then
14441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * it can now leave promiscuous mode.
14451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
14461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev_set_promiscuity(bond->curr_active_slave->dev, -1);
14471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bond_info->primary_is_promisc = 0;
14481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1449d0e81b7e2246a41d068ecaf15aac9de570816d63Jay Vosburgh			rtnl_unlock();
1450d0e81b7e2246a41d068ecaf15aac9de570816d63Jay Vosburgh			read_lock(&bond->lock);
1451d0e81b7e2246a41d068ecaf15aac9de570816d63Jay Vosburgh		}
14521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (bond_info->rlb_rebalance) {
14541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bond_info->rlb_rebalance = 0;
14551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rlb_rebalance(bond);
14561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
14571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* check if clients need updating */
14591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (bond_info->rx_ntt) {
14601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (bond_info->rlb_update_delay_counter) {
14611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				--bond_info->rlb_update_delay_counter;
14621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
14631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				rlb_update_rx_clients(bond);
14641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (bond_info->rlb_update_retry_counter) {
14651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					--bond_info->rlb_update_retry_counter;
14661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				} else {
14671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					bond_info->rx_ntt = 0;
14681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
14691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
14701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
14711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsre_arm:
1474e6d265e8504ab4a3368b8645d318b344ee88b280Jay Vosburgh	queue_delayed_work(bond->wq, &bond->alb_work, alb_delta_in_ticks);
1475e6d265e8504ab4a3368b8645d318b344ee88b280Jay Vosburgh
14761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	read_unlock(&bond->lock);
14771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* assumption: called before the slave is attached to the bond
14801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and not locked by the bond lock
14811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
14821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint bond_alb_init_slave(struct bonding *bond, struct slave *slave)
14831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
14841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int res;
14851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1486b924551bed09f61b64f21bffe241afc5526b091aJiri Bohac	res = alb_set_slave_mac_addr(slave, slave->perm_hwaddr);
14871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (res) {
14881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return res;
14891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* caller must hold the bond lock for write since the mac addresses
14921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * are compared and may be swapped.
14931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
14946603a6f25e4bca922a7dfbf0bf03072d98850176Jay Vosburgh	read_lock(&bond->lock);
14951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	res = alb_handle_addr_collision_on_attach(bond, slave);
14971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14986603a6f25e4bca922a7dfbf0bf03072d98850176Jay Vosburgh	read_unlock(&bond->lock);
14991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (res) {
15011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return res;
15021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tlb_init_slave(slave);
15051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* order a rebalance ASAP */
15071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bond->alb_info.tx_rebalance_counter = BOND_TLB_REBALANCE_TICKS;
15081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (bond->alb_info.rlb_enabled) {
15101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bond->alb_info.rlb_rebalance = 1;
15111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
15141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15162543331d367c9fe54f4ba73300894bc21e0a08f4Jay Vosburgh/*
15172543331d367c9fe54f4ba73300894bc21e0a08f4Jay Vosburgh * Remove slave from tlb and rlb hash tables, and fix up MAC addresses
15182543331d367c9fe54f4ba73300894bc21e0a08f4Jay Vosburgh * if necessary.
15192543331d367c9fe54f4ba73300894bc21e0a08f4Jay Vosburgh *
15202543331d367c9fe54f4ba73300894bc21e0a08f4Jay Vosburgh * Caller must hold RTNL and no other locks
15212543331d367c9fe54f4ba73300894bc21e0a08f4Jay Vosburgh */
15221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid bond_alb_deinit_slave(struct bonding *bond, struct slave *slave)
15231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
15241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (bond->slave_cnt > 1) {
15251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		alb_change_hw_addr_on_detach(bond, slave);
15261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tlb_clear_slave(bond, slave, 0);
15291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (bond->alb_info.rlb_enabled) {
15311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bond->alb_info.next_rx_slave = NULL;
15321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rlb_clear_slave(bond, slave);
15331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Caller must hold bond lock for read */
15371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid bond_alb_handle_link_change(struct bonding *bond, struct slave *slave, char link)
15381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
15391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
15401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (link == BOND_LINK_DOWN) {
15421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tlb_clear_slave(bond, slave, 0);
15431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (bond->alb_info.rlb_enabled) {
15441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rlb_clear_slave(bond, slave);
15451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
15461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else if (link == BOND_LINK_UP) {
15471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* order a rebalance ASAP */
15481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bond_info->tx_rebalance_counter = BOND_TLB_REBALANCE_TICKS;
15491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (bond->alb_info.rlb_enabled) {
15501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bond->alb_info.rlb_rebalance = 1;
15511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* If the updelay module parameter is smaller than the
15521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * forwarding delay of the switch the rebalance will
15531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * not work because the rebalance arp replies will
15541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * not be forwarded to the clients..
15551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
15561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
15571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
15611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * bond_alb_handle_active_change - assign new curr_active_slave
15621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @bond: our bonding struct
15631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @new_slave: new slave to assign
15641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
15651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set the bond->curr_active_slave to @new_slave and handle
15661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * mac address swapping and promiscuity changes as needed.
15671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1568059fe7a578fba5bbb0fdc0365bfcf6218fa25eb0Jay Vosburgh * If new_slave is NULL, caller must hold curr_slave_lock or
1569059fe7a578fba5bbb0fdc0365bfcf6218fa25eb0Jay Vosburgh * bond->lock for write.
1570059fe7a578fba5bbb0fdc0365bfcf6218fa25eb0Jay Vosburgh *
1571059fe7a578fba5bbb0fdc0365bfcf6218fa25eb0Jay Vosburgh * If new_slave is not NULL, caller must hold RTNL, bond->lock for
1572059fe7a578fba5bbb0fdc0365bfcf6218fa25eb0Jay Vosburgh * read and curr_slave_lock for write.  Processing here may sleep, so
1573059fe7a578fba5bbb0fdc0365bfcf6218fa25eb0Jay Vosburgh * no other locks may be held.
15741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
15751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave)
15761f78d9f94539b8806b81057e75025f2bac7d7cccHannes Eder	__releases(&bond->curr_slave_lock)
15771f78d9f94539b8806b81057e75025f2bac7d7cccHannes Eder	__releases(&bond->lock)
15781f78d9f94539b8806b81057e75025f2bac7d7cccHannes Eder	__acquires(&bond->lock)
15791f78d9f94539b8806b81057e75025f2bac7d7cccHannes Eder	__acquires(&bond->curr_slave_lock)
15801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
15811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct slave *swap_slave;
15821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
15831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (bond->curr_active_slave == new_slave) {
15851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
15861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (bond->curr_active_slave && bond->alb_info.primary_is_promisc) {
15891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_set_promiscuity(bond->curr_active_slave->dev, -1);
15901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bond->alb_info.primary_is_promisc = 0;
15911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bond->alb_info.rlb_promisc_timeout_counter = 0;
15921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	swap_slave = bond->curr_active_slave;
15951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bond->curr_active_slave = new_slave;
15961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!new_slave || (bond->slave_cnt == 0)) {
15981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
15991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
16001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* set the new curr_active_slave to the bonds mac address
16021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * i.e. swap mac addresses of old curr_active_slave and new curr_active_slave
16031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
16041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!swap_slave) {
16051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct slave *tmp_slave;
16061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* find slave that is holding the bond's mac address */
16071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bond_for_each_slave(bond, tmp_slave, i) {
1608885a136c52a8871175477baf3903e1c38751b35aEric Dumazet			if (!compare_ether_addr_64bits(tmp_slave->dev->dev_addr,
1609885a136c52a8871175477baf3903e1c38751b35aEric Dumazet						       bond->dev->dev_addr)) {
16101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				swap_slave = tmp_slave;
16111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
16121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
16131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
16141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
16151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1616059fe7a578fba5bbb0fdc0365bfcf6218fa25eb0Jay Vosburgh	/*
1617059fe7a578fba5bbb0fdc0365bfcf6218fa25eb0Jay Vosburgh	 * Arrange for swap_slave and new_slave to temporarily be
1618059fe7a578fba5bbb0fdc0365bfcf6218fa25eb0Jay Vosburgh	 * ignored so we can mess with their MAC addresses without
1619059fe7a578fba5bbb0fdc0365bfcf6218fa25eb0Jay Vosburgh	 * fear of interference from transmit activity.
1620059fe7a578fba5bbb0fdc0365bfcf6218fa25eb0Jay Vosburgh	 */
1621059fe7a578fba5bbb0fdc0365bfcf6218fa25eb0Jay Vosburgh	if (swap_slave) {
1622059fe7a578fba5bbb0fdc0365bfcf6218fa25eb0Jay Vosburgh		tlb_clear_slave(bond, swap_slave, 1);
1623059fe7a578fba5bbb0fdc0365bfcf6218fa25eb0Jay Vosburgh	}
1624059fe7a578fba5bbb0fdc0365bfcf6218fa25eb0Jay Vosburgh	tlb_clear_slave(bond, new_slave, 1);
1625059fe7a578fba5bbb0fdc0365bfcf6218fa25eb0Jay Vosburgh
1626059fe7a578fba5bbb0fdc0365bfcf6218fa25eb0Jay Vosburgh	write_unlock_bh(&bond->curr_slave_lock);
1627059fe7a578fba5bbb0fdc0365bfcf6218fa25eb0Jay Vosburgh	read_unlock(&bond->lock);
1628059fe7a578fba5bbb0fdc0365bfcf6218fa25eb0Jay Vosburgh
1629e0138a66e18c6755ee29ce13b3f1142af775dc5fJay Vosburgh	ASSERT_RTNL();
1630e0138a66e18c6755ee29ce13b3f1142af775dc5fJay Vosburgh
16311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* curr_active_slave must be set before calling alb_swap_mac_addr */
16321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (swap_slave) {
16331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* swap mac address */
16341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		alb_swap_mac_addr(bond, swap_slave, new_slave);
16351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
16361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* set the new_slave to the bond mac address */
1637b924551bed09f61b64f21bffe241afc5526b091aJiri Bohac		alb_set_slave_mac_addr(new_slave, bond->dev->dev_addr);
1638059fe7a578fba5bbb0fdc0365bfcf6218fa25eb0Jay Vosburgh	}
1639059fe7a578fba5bbb0fdc0365bfcf6218fa25eb0Jay Vosburgh
1640059fe7a578fba5bbb0fdc0365bfcf6218fa25eb0Jay Vosburgh	if (swap_slave) {
1641059fe7a578fba5bbb0fdc0365bfcf6218fa25eb0Jay Vosburgh		alb_fasten_mac_swap(bond, swap_slave, new_slave);
16422543331d367c9fe54f4ba73300894bc21e0a08f4Jay Vosburgh		read_lock(&bond->lock);
1643059fe7a578fba5bbb0fdc0365bfcf6218fa25eb0Jay Vosburgh	} else {
16442543331d367c9fe54f4ba73300894bc21e0a08f4Jay Vosburgh		read_lock(&bond->lock);
16451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		alb_send_learning_packets(new_slave, bond->dev->dev_addr);
16461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1647059fe7a578fba5bbb0fdc0365bfcf6218fa25eb0Jay Vosburgh
1648059fe7a578fba5bbb0fdc0365bfcf6218fa25eb0Jay Vosburgh	write_lock_bh(&bond->curr_slave_lock);
16491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1651059fe7a578fba5bbb0fdc0365bfcf6218fa25eb0Jay Vosburgh/*
1652059fe7a578fba5bbb0fdc0365bfcf6218fa25eb0Jay Vosburgh * Called with RTNL
1653059fe7a578fba5bbb0fdc0365bfcf6218fa25eb0Jay Vosburgh */
16541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint bond_alb_set_mac_address(struct net_device *bond_dev, void *addr)
16551f78d9f94539b8806b81057e75025f2bac7d7cccHannes Eder	__acquires(&bond->lock)
1656815bcc2719c12b6f5b511706e2d19728e07f0b02Jay Vosburgh	__releases(&bond->lock)
16571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1658454d7c9b14e20fd1949e2686e9de4a2926e01476Wang Chen	struct bonding *bond = netdev_priv(bond_dev);
16591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sockaddr *sa = addr;
16601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct slave *slave, *swap_slave;
16611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int res;
16621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
16631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!is_valid_ether_addr(sa->sa_data)) {
16651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EADDRNOTAVAIL;
16661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
16671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	res = alb_set_mac_address(bond, addr);
16691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (res) {
16701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return res;
16711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
16721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memcpy(bond_dev->dev_addr, sa->sa_data, bond_dev->addr_len);
16741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* If there is no curr_active_slave there is nothing else to do.
16761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Otherwise we'll need to pass the new address to it and handle
16771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * duplications.
16781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
16791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!bond->curr_active_slave) {
16801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
16811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
16821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	swap_slave = NULL;
16841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bond_for_each_slave(bond, slave, i) {
1686885a136c52a8871175477baf3903e1c38751b35aEric Dumazet		if (!compare_ether_addr_64bits(slave->dev->dev_addr,
1687885a136c52a8871175477baf3903e1c38751b35aEric Dumazet					       bond_dev->dev_addr)) {
16881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			swap_slave = slave;
16891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
16901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
16911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
16921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (swap_slave) {
16941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		alb_swap_mac_addr(bond, swap_slave, bond->curr_active_slave);
1695059fe7a578fba5bbb0fdc0365bfcf6218fa25eb0Jay Vosburgh		alb_fasten_mac_swap(bond, swap_slave, bond->curr_active_slave);
16961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
1697b924551bed09f61b64f21bffe241afc5526b091aJiri Bohac		alb_set_slave_mac_addr(bond->curr_active_slave, bond_dev->dev_addr);
16981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1699815bcc2719c12b6f5b511706e2d19728e07f0b02Jay Vosburgh		read_lock(&bond->lock);
17001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		alb_send_learning_packets(bond->curr_active_slave, bond_dev->dev_addr);
17011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (bond->alb_info.rlb_enabled) {
17021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* inform clients mac address has changed */
17031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rlb_req_update_slave_clients(bond, bond->curr_active_slave);
17041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1705815bcc2719c12b6f5b511706e2d19728e07f0b02Jay Vosburgh		read_unlock(&bond->lock);
17061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
17071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
17091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid bond_alb_clear_vlan(struct bonding *bond, unsigned short vlan_id)
17121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
17131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (bond->alb_info.current_alb_vlan &&
17141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    (bond->alb_info.current_alb_vlan->vlan_id == vlan_id)) {
17151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bond->alb_info.current_alb_vlan = NULL;
17161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
17171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (bond->alb_info.rlb_enabled) {
17191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rlb_clear_vlan(bond, vlan_id);
17201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
17211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1723