net: deliver skbs on inactive slaves to exact matches
authorJohn Fastabend <john.r.fastabend@intel.com>
Thu, 3 Jun 2010 09:30:11 +0000 (09:30 +0000)
committerDavid S. Miller <davem@davemloft.net>
Fri, 11 Jun 2010 05:23:34 +0000 (22:23 -0700)
Currently, the accelerated receive path for VLAN's will
drop packets if the real device is an inactive slave and
is not one of the special pkts tested for in
skb_bond_should_drop().  This behavior is different then
the non-accelerated path and for pkts over a bonded vlan.

For example,

vlanx -> bond0 -> ethx

will be dropped in the vlan path and not delivered to any
packet handlers at all.  However,

bond0 -> vlanx -> ethx

and

bond0 -> ethx

will be delivered to handlers that match the exact dev,
because the VLAN path checks the real_dev which is not a
slave and netif_recv_skb() doesn't drop frames but only
delivers them to exact matches.

This patch adds a sk_buff flag which is used for tagging
skbs that would previously been dropped and allows the
skb to continue to skb_netif_recv().  Here we add
logic to check for the deliver_no_wcard flag and if it
is set only deliver to handlers that match exactly.  This
makes both paths above consistent and gives pkt handlers
a way to identify skbs that come from inactive slaves.
Without this patch in some configurations skbs will be
delivered to handlers with exact matches and in others
be dropped out right in the vlan path.

I have tested the following 4 configurations in failover modes
and load balancing modes.

# bond0 -> ethx

# vlanx -> bond0 -> ethx

# bond0 -> vlanx -> ethx

# bond0 -> ethx
            |
  vlanx -> --

Signed-off-by: John Fastabend <john.r.fastabend@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/linux/skbuff.h
net/8021q/vlan_core.c
net/core/dev.c

index bf243fc54959098e49d6a77dac955aea8cf9d4b6..f89e7fd59a4c4029a5e301b30c14df0ee7ae2699 100644 (file)
@@ -380,7 +380,10 @@ struct sk_buff {
        kmemcheck_bitfield_begin(flags2);
        __u16                   queue_mapping:16;
 #ifdef CONFIG_IPV6_NDISC_NODETYPE
-       __u8                    ndisc_nodetype:2;
+       __u8                    ndisc_nodetype:2,
+                               deliver_no_wcard:1;
+#else
+       __u8                    deliver_no_wcard:1;
 #endif
        kmemcheck_bitfield_end(flags2);
 
index bd537fc10254c9fbb6cf3872e8488bba1809781b..50f58f5f1c3491f775a5ac6c97ea32c5c5b23674 100644 (file)
@@ -12,7 +12,7 @@ int __vlan_hwaccel_rx(struct sk_buff *skb, struct vlan_group *grp,
                return NET_RX_DROP;
 
        if (skb_bond_should_drop(skb, ACCESS_ONCE(skb->dev->master)))
-               goto drop;
+               skb->deliver_no_wcard = 1;
 
        skb->skb_iif = skb->dev->ifindex;
        __vlan_hwaccel_put_tag(skb, vlan_tci);
@@ -84,7 +84,7 @@ vlan_gro_common(struct napi_struct *napi, struct vlan_group *grp,
        struct sk_buff *p;
 
        if (skb_bond_should_drop(skb, ACCESS_ONCE(skb->dev->master)))
-               goto drop;
+               skb->deliver_no_wcard = 1;
 
        skb->skb_iif = skb->dev->ifindex;
        __vlan_hwaccel_put_tag(skb, vlan_tci);
index 14a85682af38298e357e8d64f0c97f459e76e1cd..2b3bf53bc687aab3c9cfb32cce902eaebb3c18da 100644 (file)
@@ -2810,13 +2810,24 @@ static int __netif_receive_skb(struct sk_buff *skb)
        if (!skb->skb_iif)
                skb->skb_iif = skb->dev->ifindex;
 
+       /*
+        * bonding note: skbs received on inactive slaves should only
+        * be delivered to pkt handlers that are exact matches.  Also
+        * the deliver_no_wcard flag will be set.  If packet handlers
+        * are sensitive to duplicate packets these skbs will need to
+        * be dropped at the handler.  The vlan accel path may have
+        * already set the deliver_no_wcard flag.
+        */
        null_or_orig = NULL;
        orig_dev = skb->dev;
        master = ACCESS_ONCE(orig_dev->master);
-       if (master) {
-               if (skb_bond_should_drop(skb, master))
+       if (skb->deliver_no_wcard)
+               null_or_orig = orig_dev;
+       else if (master) {
+               if (skb_bond_should_drop(skb, master)) {
+                       skb->deliver_no_wcard = 1;
                        null_or_orig = orig_dev; /* deliver only exact match */
-               else
+               else
                        skb->dev = master;
        }