bridge: Add multicast data-path hooks
authorHerbert Xu <herbert@gondor.apana.org.au>
Sat, 27 Feb 2010 19:41:48 +0000 (19:41 +0000)
committerDavid S. Miller <davem@davemloft.net>
Sun, 28 Feb 2010 08:49:45 +0000 (00:49 -0800)
This patch finally hooks up the multicast snooping module to the
data path.  In particular, all multicast packets passing through
the bridge are fed into the module and switched by it.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/bridge/br_device.c
net/bridge/br_input.c

index 91dffe7574d6724ab0dd2ca4057f2989f56e5494..eb7062d2e9e5d28168fe2dcbdc3ec2f44bc9f4c9 100644 (file)
@@ -25,6 +25,7 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
        struct net_bridge *br = netdev_priv(dev);
        const unsigned char *dest = skb->data;
        struct net_bridge_fdb_entry *dst;
+       struct net_bridge_mdb_entry *mdst;
 
        BR_INPUT_SKB_CB(skb)->brdev = dev;
 
@@ -34,13 +35,21 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
        skb_reset_mac_header(skb);
        skb_pull(skb, ETH_HLEN);
 
-       if (dest[0] & 1)
-               br_flood_deliver(br, skb);
-       else if ((dst = __br_fdb_get(br, dest)) != NULL)
+       if (dest[0] & 1) {
+               if (br_multicast_rcv(br, NULL, skb))
+                       goto out;
+
+               mdst = br_mdb_get(br, skb);
+               if (mdst || BR_INPUT_SKB_CB(skb)->mrouters_only)
+                       br_multicast_deliver(mdst, skb);
+               else
+                       br_flood_deliver(br, skb);
+       } else if ((dst = __br_fdb_get(br, dest)) != NULL)
                br_deliver(dst->dst, skb);
        else
                br_flood_deliver(br, skb);
 
+out:
        return NETDEV_TX_OK;
 }
 
index edfdaef44296184e82390ae82fdfef01da626eda..53b39851d87d475ecdbfbf9b94fa6eb8072d5f40 100644 (file)
@@ -41,6 +41,7 @@ int br_handle_frame_finish(struct sk_buff *skb)
        struct net_bridge_port *p = rcu_dereference(skb->dev->br_port);
        struct net_bridge *br;
        struct net_bridge_fdb_entry *dst;
+       struct net_bridge_mdb_entry *mdst;
        struct sk_buff *skb2;
 
        if (!p || p->state == BR_STATE_DISABLED)
@@ -50,6 +51,10 @@ int br_handle_frame_finish(struct sk_buff *skb)
        br = p->br;
        br_fdb_update(br, p, eth_hdr(skb)->h_source);
 
+       if (is_multicast_ether_addr(dest) &&
+           br_multicast_rcv(br, p, skb))
+               goto drop;
+
        if (p->state == BR_STATE_LEARNING)
                goto drop;
 
@@ -64,8 +69,19 @@ int br_handle_frame_finish(struct sk_buff *skb)
        dst = NULL;
 
        if (is_multicast_ether_addr(dest)) {
+               mdst = br_mdb_get(br, skb);
+               if (mdst || BR_INPUT_SKB_CB(skb)->mrouters_only) {
+                       if ((mdst && !hlist_unhashed(&mdst->mglist)) ||
+                           br_multicast_is_router(br))
+                               skb2 = skb;
+                       br_multicast_forward(mdst, skb, skb2);
+                       skb = NULL;
+                       if (!skb2)
+                               goto out;
+               } else
+                       skb2 = skb;
+
                br->dev->stats.multicast++;
-               skb2 = skb;
        } else if ((dst = __br_fdb_get(br, dest)) && dst->is_local) {
                skb2 = skb;
                /* Do not forward the packet since it's local. */