Skip to content

Commit

Permalink
bridge: Add multicast forwarding functions
Browse files Browse the repository at this point in the history
This patch adds code to perform selective multicast forwarding.

We forward multicast traffic to a set of ports plus all multicast
router ports.  In order to avoid duplications among these two
sets of ports, we order all ports by the numeric value of their
pointers.  The two lists are then walked in lock-step to eliminate
duplicates.

Signed-off-by: Herbert Xu <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
herbertx authored and davem330 committed Feb 28, 2010
1 parent eb1d164 commit 5cb5e94
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 0 deletions.
67 changes: 67 additions & 0 deletions net/bridge/br_forward.c
Original file line number Diff line number Diff line change
Expand Up @@ -186,3 +186,70 @@ void br_flood_forward(struct net_bridge *br, struct sk_buff *skb,
{
br_flood(br, skb, skb2, __br_forward);
}

#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
/* called with rcu_read_lock */
static void br_multicast_flood(struct net_bridge_mdb_entry *mdst,
struct sk_buff *skb, struct sk_buff *skb0,
void (*__packet_hook)(
const struct net_bridge_port *p,
struct sk_buff *skb))
{
struct net_device *dev = BR_INPUT_SKB_CB(skb)->brdev;
struct net_bridge *br = netdev_priv(dev);
struct net_bridge_port *port;
struct net_bridge_port *lport, *rport;
struct net_bridge_port *prev;
struct net_bridge_port_group *p;
struct hlist_node *rp;

prev = NULL;

rp = br->router_list.first;
p = mdst ? mdst->ports : NULL;
while (p || rp) {
lport = p ? p->port : NULL;
rport = rp ? hlist_entry(rp, struct net_bridge_port, rlist) :
NULL;

port = (unsigned long)lport > (unsigned long)rport ?
lport : rport;

prev = maybe_deliver(prev, port, skb, __packet_hook);
if (IS_ERR(prev))
goto out;

if ((unsigned long)lport >= (unsigned long)port)
p = p->next;
if ((unsigned long)rport >= (unsigned long)port)
rp = rp->next;
}

if (!prev)
goto out;

if (skb0)
deliver_clone(prev, skb, __packet_hook);
else
__packet_hook(prev, skb);
return;

out:
if (!skb0)
kfree_skb(skb);
}

/* called with rcu_read_lock */
void br_multicast_deliver(struct net_bridge_mdb_entry *mdst,
struct sk_buff *skb)
{
br_multicast_flood(mdst, skb, NULL, __br_deliver);
}

/* called with rcu_read_lock */
void br_multicast_forward(struct net_bridge_mdb_entry *mdst,
struct sk_buff *skb, struct sk_buff *skb2)
{
br_multicast_flood(mdst, skb, skb2, __br_forward);
}
#endif
15 changes: 15 additions & 0 deletions net/bridge/br_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,10 @@ extern void br_multicast_disable_port(struct net_bridge_port *port);
extern void br_multicast_init(struct net_bridge *br);
extern void br_multicast_open(struct net_bridge *br);
extern void br_multicast_stop(struct net_bridge *br);
extern void br_multicast_deliver(struct net_bridge_mdb_entry *mdst,
struct sk_buff *skb);
extern void br_multicast_forward(struct net_bridge_mdb_entry *mdst,
struct sk_buff *skb, struct sk_buff *skb2);
#else
static inline int br_multicast_rcv(struct net_bridge *br,
struct net_bridge_port *port,
Expand Down Expand Up @@ -334,6 +338,17 @@ static inline void br_multicast_open(struct net_bridge *br)
static inline void br_multicast_stop(struct net_bridge *br)
{
}

static inline void br_multicast_deliver(struct net_bridge_mdb_entry *mdst,
struct sk_buff *skb)
{
}

static inline void br_multicast_forward(struct net_bridge_mdb_entry *mdst,
struct sk_buff *skb,
struct sk_buff *skb2)
{
}
#endif

static inline bool br_multicast_is_router(struct net_bridge *br)
Expand Down

0 comments on commit 5cb5e94

Please sign in to comment.