}
/* Forward declaration */
-static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[]);
+static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[],
+ bool strict_match);
static void rlb_purge_src_ip(struct bonding *bond, struct arp_pkt *arp);
static void rlb_src_unlink(struct bonding *bond, u32 index);
static void rlb_src_link(struct bonding *bond, u32 ip_src_hash,
bond->alb_info.rlb_promisc_timeout_counter = 0;
- alb_send_learning_packets(bond->curr_active_slave, addr);
+ alb_send_learning_packets(bond->curr_active_slave, addr, true);
}
/* slave being removed should not be active at this point
dev_queue_xmit(skb);
}
-
-static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[])
+static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[],
+ bool strict_match)
{
struct bonding *bond = bond_get_bond_by_slave(slave);
struct net_device *upper;
/* loop through vlans and send one packet for each */
rcu_read_lock();
netdev_for_each_all_upper_dev_rcu(bond->dev, upper, iter) {
- if (is_vlan_dev(upper) && vlan_get_encap_level(upper) == 0)
- alb_send_lp_vid(slave, mac_addr,
- vlan_dev_vlan_proto(upper),
- vlan_dev_vlan_id(upper));
+ if (is_vlan_dev(upper) && vlan_get_encap_level(upper) == 0) {
+ if (strict_match &&
+ ether_addr_equal_64bits(mac_addr,
+ upper->dev_addr)) {
+ alb_send_lp_vid(slave, mac_addr,
+ vlan_dev_vlan_proto(upper),
+ vlan_dev_vlan_id(upper));
+ } else if (!strict_match) {
+ alb_send_lp_vid(slave, upper->dev_addr,
+ vlan_dev_vlan_proto(upper),
+ vlan_dev_vlan_id(upper));
+ }
+ }
}
rcu_read_unlock();
}
/* fasten the change in the switch */
if (SLAVE_IS_OK(slave1)) {
- alb_send_learning_packets(slave1, slave1->dev->dev_addr);
+ alb_send_learning_packets(slave1, slave1->dev->dev_addr, false);
if (bond->alb_info.rlb_enabled) {
/* inform the clients that the mac address
* has changed
}
if (SLAVE_IS_OK(slave2)) {
- alb_send_learning_packets(slave2, slave2->dev->dev_addr);
+ alb_send_learning_packets(slave2, slave2->dev->dev_addr, false);
if (bond->alb_info.rlb_enabled) {
/* inform the clients that the mac address
* has changed
/* send learning packets */
if (bond_info->lp_counter >= BOND_ALB_LP_TICKS(bond)) {
+ bool strict_match;
+
/* change of curr_active_slave involves swapping of mac addresses.
* in order to avoid this swapping from happening while
* sending the learning packets, the curr_slave_lock must be held for
*/
read_lock(&bond->curr_slave_lock);
- bond_for_each_slave_rcu(bond, slave, iter)
- alb_send_learning_packets(slave, slave->dev->dev_addr);
+ bond_for_each_slave_rcu(bond, slave, iter) {
+ /* If updating current_active, use all currently
+ * user mac addreses (!strict_match). Otherwise, only
+ * use mac of the slave device.
+ */
+ strict_match = (slave != bond->curr_active_slave);
+ alb_send_learning_packets(slave, slave->dev->dev_addr,
+ strict_match);
+ }
read_unlock(&bond->curr_slave_lock);
} else {
/* set the new_slave to the bond mac address */
alb_set_slave_mac_addr(new_slave, bond->dev->dev_addr);
- alb_send_learning_packets(new_slave, bond->dev->dev_addr);
+ alb_send_learning_packets(new_slave, bond->dev->dev_addr,
+ false);
}
write_lock_bh(&bond->curr_slave_lock);
alb_set_slave_mac_addr(bond->curr_active_slave, bond_dev->dev_addr);
read_lock(&bond->lock);
- alb_send_learning_packets(bond->curr_active_slave, bond_dev->dev_addr);
+ alb_send_learning_packets(bond->curr_active_slave,
+ bond_dev->dev_addr, false);
if (bond->alb_info.rlb_enabled) {
/* inform clients mac address has changed */
rlb_req_update_slave_clients(bond, bond->curr_active_slave);