summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/net/bonding/bond_alb.c21
-rw-r--r--drivers/net/bonding/bond_main.c8
-rw-r--r--drivers/net/bonding/bonding.h24
-rw-r--r--drivers/net/macvlan.c7
4 files changed, 53 insertions, 7 deletions
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index 7bbbf1ca0887..76c0dade233f 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -755,7 +755,7 @@ static struct slave *rlb_arp_xmit(struct sk_buff *skb, struct bonding *bond)
/* Don't modify or load balance ARPs that do not originate locally
* (e.g.,arrive via a bridge).
*/
- if (!bond_slave_has_mac_rcu(bond, arp->mac_src))
+ if (!bond_slave_has_mac_rx(bond, arp->mac_src))
return NULL;
if (arp->op_code == htons(ARPOP_REPLY)) {
@@ -1039,11 +1039,14 @@ static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[],
struct bonding *bond = bond_get_bond_by_slave(slave);
struct net_device *upper;
struct list_head *iter;
+ struct bond_vlan_tag tags[BOND_MAX_VLAN_ENCAP];
/* send untagged */
alb_send_lp_vid(slave, mac_addr, 0, 0);
- /* loop through vlans and send one packet for each */
+ /* loop through all devices and see if we need to send a packet
+ * for that device.
+ */
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) {
@@ -1059,6 +1062,16 @@ static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[],
vlan_dev_vlan_id(upper));
}
}
+
+ /* If this is a macvlan device, then only send updates
+ * when strict_match is turned off.
+ */
+ if (netif_is_macvlan(upper) && !strict_match) {
+ memset(tags, 0, sizeof(tags));
+ bond_verify_device_path(bond->dev, upper, tags);
+ alb_send_lp_vid(slave, upper->dev_addr,
+ tags[0].vlan_proto, tags[0].vlan_id);
+ }
}
rcu_read_unlock();
}
@@ -1560,8 +1573,10 @@ void bond_alb_monitor(struct work_struct *work)
/* If updating current_active, use all currently
* user mac addreses (!strict_match). Otherwise, only
* use mac of the slave device.
+ * In RLB mode, we always use strict matches.
*/
- strict_match = (slave != bond->curr_active_slave);
+ strict_match = (slave != bond->curr_active_slave ||
+ bond_info->rlb_enabled);
alb_send_learning_packets(slave, slave->dev->dev_addr,
strict_match);
}
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 59a12c61ceb4..04f35f960cb8 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -2206,9 +2206,9 @@ static void bond_arp_send(struct net_device *slave_dev, int arp_op,
* When the path is validated, collect any vlan information in the
* path.
*/
-static bool bond_verify_device_path(struct net_device *start_dev,
- struct net_device *end_dev,
- struct bond_vlan_tag *tags)
+bool bond_verify_device_path(struct net_device *start_dev,
+ struct net_device *end_dev,
+ struct bond_vlan_tag *tags)
{
struct net_device *upper;
struct list_head *iter;
@@ -3945,7 +3945,7 @@ void bond_setup(struct net_device *bond_dev)
/* Initialize the device options */
bond_dev->tx_queue_len = 0;
bond_dev->flags |= IFF_MASTER|IFF_MULTICAST;
- bond_dev->priv_flags |= IFF_BONDING;
+ bond_dev->priv_flags |= IFF_BONDING | IFF_UNICAST_FLT;
bond_dev->priv_flags &= ~(IFF_XMIT_DST_RELEASE | IFF_TX_SKB_SHARING);
/* At first, we block adding VLANs. That's the only way to
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index ea64aa2f8b95..0b4d9cde0b05 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -516,6 +516,9 @@ void bond_netlink_fini(void);
struct net_device *bond_option_active_slave_get_rcu(struct bonding *bond);
struct net_device *bond_option_active_slave_get(struct bonding *bond);
const char *bond_slave_link_status(s8 link);
+bool bond_verify_device_path(struct net_device *start_dev,
+ struct net_device *end_dev,
+ struct bond_vlan_tag *tags);
#ifdef CONFIG_PROC_FS
void bond_create_proc_entry(struct bonding *bond);
@@ -567,6 +570,27 @@ static inline struct slave *bond_slave_has_mac_rcu(struct bonding *bond,
return NULL;
}
+/* Caller must hold rcu_read_lock() for read */
+static inline bool bond_slave_has_mac_rx(struct bonding *bond, const u8 *mac)
+{
+ struct list_head *iter;
+ struct slave *tmp;
+ struct netdev_hw_addr *ha;
+
+ bond_for_each_slave_rcu(bond, tmp, iter)
+ if (ether_addr_equal_64bits(mac, tmp->dev->dev_addr))
+ return true;
+
+ if (netdev_uc_empty(bond->dev))
+ return false;
+
+ netdev_for_each_uc_addr(ha, bond->dev)
+ if (ether_addr_equal_64bits(mac, ha->addr))
+ return true;
+
+ return false;
+}
+
/* Check if the ip is present in arp ip list, or first free slot if ip == 0
* Returns -1 if not found, index if found
*/
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index eee9106d1da1..453d55a02492 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -1209,6 +1209,13 @@ static int macvlan_device_event(struct notifier_block *unused,
case NETDEV_PRE_TYPE_CHANGE:
/* Forbid underlaying device to change its type. */
return NOTIFY_BAD;
+
+ case NETDEV_NOTIFY_PEERS:
+ case NETDEV_BONDING_FAILOVER:
+ case NETDEV_RESEND_IGMP:
+ /* Propagate to all vlans */
+ list_for_each_entry(vlan, &port->vlans, list)
+ call_netdevice_notifiers(event, vlan->dev);
}
return NOTIFY_DONE;
}