Merge branch 'bonding-macvlan'

Vlad Yasevich says:

====================
Fix support for macvlan devices on top bonding

Currently, macvlan devices do not work well over bond interfaces.
Everything works well, untill a failover is triggered in the bond
device and then macvlan becomes unreachble untill arp entries
are flushed.   This series adds needed functionality to
handle correct notifications and update switches with mac addresses
assigned to macvlans.

The first patch simply addes IFF_UNICAST_FLT flag to bonds since they
already correctly manage the unicast filter list of the slaves, so
we might as well prevent the bond from needlessly going into promiscuous
mode.

The second patch adds notifier handler to macvlan to trigger correct
ARP notifications.

The third patch adds handling for TLB and RLB modes that use special
ETH_P_LOOPBACK type packets to teach switch about mac addresses.
It also allow ARPs for the macvlan mac addresses to be handled by
RLB mode.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2014-06-04 15:14:17 -07:00
commit 6579867c8b
4 changed files with 53 additions and 7 deletions

View File

@ -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);
}

View File

@ -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

View File

@ -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
*/

View File

@ -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;
}