|
@@ -82,7 +82,8 @@ static inline struct arp_pkt *arp_pkt(const struct sk_buff *skb)
|
|
|
}
|
|
|
|
|
|
/* 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,
|
|
@@ -459,7 +460,7 @@ static void rlb_teach_disabled_mac_on_primary(struct bonding *bond, u8 addr[])
|
|
|
|
|
|
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
|
|
@@ -1032,8 +1033,8 @@ static void alb_send_lp_vid(struct slave *slave, u8 mac_addr[],
|
|
|
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;
|
|
@@ -1045,10 +1046,19 @@ static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[])
|
|
|
/* 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();
|
|
|
}
|
|
@@ -1108,7 +1118,7 @@ static void alb_fasten_mac_swap(struct bonding *bond, struct slave *slave1,
|
|
|
|
|
|
/* 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
|
|
@@ -1120,7 +1130,7 @@ static void alb_fasten_mac_swap(struct bonding *bond, struct slave *slave1,
|
|
|
}
|
|
|
|
|
|
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
|
|
@@ -1491,6 +1501,8 @@ void bond_alb_monitor(struct work_struct *work)
|
|
|
|
|
|
/* 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
|
|
@@ -1498,8 +1510,15 @@ void bond_alb_monitor(struct work_struct *work)
|
|
|
*/
|
|
|
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);
|
|
|
|
|
@@ -1722,7 +1741,8 @@ void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave
|
|
|
} 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);
|
|
@@ -1765,7 +1785,8 @@ int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr)
|
|
|
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);
|