summaryrefslogtreecommitdiffstats
path: root/net/bridge/br_input.c
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2010-02-27 19:41:48 +0000
committerDavid S. Miller <davem@davemloft.net>2010-02-28 00:49:45 -0800
commitc4fcb78cf8ae55667809e54e54872a21025dd073 (patch)
tree3c0319c853f6275494d60f32fc8ade12532f13a6 /net/bridge/br_input.c
parent3fe2d7c70b747d5d968f4e8fa210676d49d40059 (diff)
bridge: Add multicast data-path hooks
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>
Diffstat (limited to 'net/bridge/br_input.c')
-rw-r--r--net/bridge/br_input.c18
1 files changed, 17 insertions, 1 deletions
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
index edfdaef4429..53b39851d87 100644
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -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. */