From: Jiri Pirko <jpirko@redhat.com> Date: Sat, 30 May 2009 08:07:40 +0200 Subject: [net] bonding: allow bond in mode balance-alb to work Message-id: 20090530060739.GA3427@psychotron.englab.brq.redhat.com O-Subject: [RHEL5.5 patch] BZ487763 net: bonding: allow bond in mode balance-alb to work properly in bridge Bugzilla: 487763 RH-Acked-by: David Miller <davem@redhat.com> RH-Acked-by: Ivan Vecera <ivecera@redhat.com> RH-Acked-by: Thomas Graf <tgraf@redhat.com> [RHEL5.5 patch] BZ487763 net: bonding: allow bond in mode balance-alb to work properly in bridge BZ487763 https://bugzilla.redhat.com/show_bug.cgi?id=487763 Description: Basically here's what's going on. In every mode, bonding interface uses the same mac address for all enslaved devices (except fail_over_mac). Only balance-alb will simultaneously use multiple MAC addresses across different slaves. When you put this kind of bond device into a bridge it will only add one of mac adresses into a hash list of mac addresses, say X. This mac address is marked as local. But this bonding interface also has mac address Y. Now then packet arrives with destination address Y, this address is not marked as local and the packed looks like it needs to be forwarded. This packet is then lost which is wrong. This patch solves the situation in the bonding without touching bridge code. For every incoming frame to bonding the destination address is compared to current address of the slave device from which tha packet came. If these two match destination address is replaced by mac address of the master. This address is known by bridge so it is delivered properly. Note that the comparsion is not made directly, it's used skb->pkt_type == PACKET_HOST instead. This is "set" previously in eth_type_trans(). Upstream: http://git.kernel.org/?p=linux/kernel/git/davem/net-next-2.6.git;a=commitdiff;h=5d4e039b2cb1ca4de9774344ea7b61ad7fa1b0a1 Brew: https://brewweb.devel.redhat.com/taskinfo?taskID=1817516 Test: Booted and tested on x86_64. Works fine. Jirka Signed-off-by: Jiri Pirko <jpirko@redhat.com> diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index c0a73b4..c2f9726 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1219,6 +1219,16 @@ static inline int netif_needs_gso(struct net_device *dev, struct sk_buff *skb) unlikely(skb->ip_summed != CHECKSUM_HW)); } +static inline void skb_bond_set_mac_by_master(struct sk_buff *skb, + struct net_device *master) +{ + if (skb->pkt_type == PACKET_HOST) { + u16 *dest = (u16 *) eth_hdr(skb)->h_dest; + + memcpy(dest, master->dev_addr, ETH_ALEN); + } +} + /* On bonding slaves other than the currently active slave, suppress * duplicates except for 802.3ad ETH_P_SLOW, alb non-mcast/bcast, and * ARP on active-backup slaves with arp_validate enabled. @@ -1232,6 +1242,14 @@ static inline int skb_bond_should_drop(struct sk_buff *skb) if (master->priv_flags & IFF_MASTER_ARPMON) dev->last_rx = jiffies; + if ((master->priv_flags & IFF_MASTER_ALB) && master->br_port) { + /* Do address unmangle. The local destination address + * will be always the one master has. Provides the right + * functionality in a bridge. + */ + skb_bond_set_mac_by_master(skb, master); + } + if (dev->priv_flags & IFF_SLAVE_INACTIVE) { if ((dev->priv_flags & IFF_SLAVE_NEEDARP) && skb->protocol == __constant_htons(ETH_P_ARP))