]> xenbits.xensource.com Git - people/ssmith/nc2-2.6.27.bak/.git/commitdiff
patch bonding-vlan-fixes.patch
authorSteven Smith <ssmith@weybridge.uk.xensource.com>
Thu, 28 May 2009 10:54:19 +0000 (11:54 +0100)
committerSteven Smith <ssmith@weybridge.uk.xensource.com>
Thu, 28 May 2009 10:54:19 +0000 (11:54 +0100)
net/core/dev.c

index e00b251c3b50f62d59c54a2d52add73aaba43ccc..a6cc3c50513535b35f756954e04e107394b42b43 100644 (file)
@@ -88,6 +88,7 @@
 #include <linux/errno.h>
 #include <linux/interrupt.h>
 #include <linux/if_ether.h>
+#include <linux/if_vlan.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/ethtool.h>
@@ -2043,6 +2044,8 @@ int netif_rx_ni(struct sk_buff *skb)
 
 EXPORT_SYMBOL(netif_rx_ni);
 
+#include <../drivers/net/bonding/bonding.h>
+
 static void net_tx_action(struct softirq_action *h)
 {
        struct softnet_data *sd = &__get_cpu_var(softnet_data);
@@ -2336,8 +2339,45 @@ int netif_receive_skb(struct sk_buff *skb)
        if (orig_dev->master) {
                if (skb_bond_should_drop(skb))
                        null_or_orig = orig_dev; /* deliver only exact match */
-               else
+               else {
                        skb->dev = orig_dev->master;
+
+                       /* The bonding driver claims to support rx vlan h/w acceleration.
+                        * It actually just assumes the slave supports it and offloads the
+                        * the responsibility for the acceleration to the slave.
+                        * If the slave does not support rx vlan h/w acceleration
+                        * then the tagged frames will end up here.
+                        * When this happens we need to emulate the rx vlan h/w acceleration
+                        * feature that is missing in the slave.
+                        */
+                       if (!(skb->dev->features & NETIF_F_HW_VLAN_RX) &&
+                           (skb->dev->master->features & NETIF_F_HW_VLAN_RX)) {
+
+                               struct bonding *bond = skb->dev->master->priv;
+                               struct vlan_group *grp = bond->vlgrp;
+                               struct ethhdr *hdr = eth_hdr(skb);
+
+                               if (hdr->h_proto == htons(ETH_P_8021Q) && grp &&
+                                   skb->len >= VLAN_ETH_HLEN) {
+                                       struct vlan_ethhdr *vhdr = vlan_eth_hdr(skb);
+                                       u16 vtag = ntohs(vhdr->h_vlan_TCI);
+
+                                       /* Reset skb->data to the start of the frame */
+                                       __skb_push(skb, skb->data - skb_mac_header(skb));
+
+                                       /* Ditch the 4 byte vlan shim */
+                                       memmove(skb_mac_header(skb) + VLAN_HLEN, skb_mac_header(skb), ETH_ALEN * 2);
+                                       __skb_pull(skb, VLAN_HLEN);
+
+                                       /* Update the skb details */
+                                       skb->protocol = eth_type_trans(skb, skb->dev);
+
+                                       /* Pass up the stack as if it came from bond0 */
+                                       vlan_hwaccel_rx(skb, grp, vtag);
+                                       return NET_RX_SUCCESS;
+                               }
+                       }
+               }
        }
 
        __get_cpu_var(netdev_rx_stat).total++;