bridge: Add core IGMP snooping support
This patch adds the core functionality of IGMP snooping support without actually hooking it up. So this patch should be a no-op as far as the bridge's external behaviour is concerned. All the new code and data is controlled by the Kconfig option BRIDGE_IGMP_SNOOPING. A run-time toggle is also available. The multicast switching is done using an hash table that is lockless on the read-side through RCU. On the write-side the new multicast_lock is used for all operations. The hash table supports dynamic growth/rehashing. The hash table will be rehashed if any chain length exceeds a preset limit. If rehashing does not reduce the maximum chain length then snooping will be disabled. These features may be added in future (in no particular order): * IGMPv3 source support * Non-querier router detection * IPv6 Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
025d89c27f
commit
eb1d164143
|
@ -31,3 +31,15 @@ config BRIDGE
|
||||||
will be called bridge.
|
will be called bridge.
|
||||||
|
|
||||||
If unsure, say N.
|
If unsure, say N.
|
||||||
|
|
||||||
|
config BRIDGE_IGMP_SNOOPING
|
||||||
|
bool "IGMP snooping"
|
||||||
|
default y
|
||||||
|
---help---
|
||||||
|
If you say Y here, then the Ethernet bridge will be able selectively
|
||||||
|
forward multicast traffic based on IGMP traffic received from each
|
||||||
|
port.
|
||||||
|
|
||||||
|
Say N to exclude this support and reduce the binary size.
|
||||||
|
|
||||||
|
If unsure, say Y.
|
||||||
|
|
|
@ -12,4 +12,6 @@ bridge-$(CONFIG_SYSFS) += br_sysfs_if.o br_sysfs_br.o
|
||||||
|
|
||||||
bridge-$(CONFIG_BRIDGE_NETFILTER) += br_netfilter.o
|
bridge-$(CONFIG_BRIDGE_NETFILTER) += br_netfilter.o
|
||||||
|
|
||||||
|
bridge-$(CONFIG_BRIDGE_IGMP_SNOOPING) += br_multicast.o
|
||||||
|
|
||||||
obj-$(CONFIG_BRIDGE_NF_EBTABLES) += netfilter/
|
obj-$(CONFIG_BRIDGE_NF_EBTABLES) += netfilter/
|
||||||
|
|
1135
net/bridge/br_multicast.c
Normal file
1135
net/bridge/br_multicast.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -57,6 +57,41 @@ struct net_bridge_fdb_entry
|
||||||
unsigned char is_static;
|
unsigned char is_static;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct net_bridge_port_group {
|
||||||
|
struct net_bridge_port *port;
|
||||||
|
struct net_bridge_port_group *next;
|
||||||
|
struct hlist_node mglist;
|
||||||
|
struct rcu_head rcu;
|
||||||
|
struct timer_list timer;
|
||||||
|
struct timer_list query_timer;
|
||||||
|
__be32 addr;
|
||||||
|
u32 queries_sent;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct net_bridge_mdb_entry
|
||||||
|
{
|
||||||
|
struct hlist_node hlist[2];
|
||||||
|
struct hlist_node mglist;
|
||||||
|
struct net_bridge *br;
|
||||||
|
struct net_bridge_port_group *ports;
|
||||||
|
struct rcu_head rcu;
|
||||||
|
struct timer_list timer;
|
||||||
|
struct timer_list query_timer;
|
||||||
|
__be32 addr;
|
||||||
|
u32 queries_sent;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct net_bridge_mdb_htable
|
||||||
|
{
|
||||||
|
struct hlist_head *mhash;
|
||||||
|
struct rcu_head rcu;
|
||||||
|
struct net_bridge_mdb_htable *old;
|
||||||
|
u32 size;
|
||||||
|
u32 max;
|
||||||
|
u32 secret;
|
||||||
|
u32 ver;
|
||||||
|
};
|
||||||
|
|
||||||
struct net_bridge_port
|
struct net_bridge_port
|
||||||
{
|
{
|
||||||
struct net_bridge *br;
|
struct net_bridge *br;
|
||||||
|
@ -84,6 +119,15 @@ struct net_bridge_port
|
||||||
|
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
#define BR_HAIRPIN_MODE 0x00000001
|
#define BR_HAIRPIN_MODE 0x00000001
|
||||||
|
|
||||||
|
#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
|
||||||
|
u32 multicast_startup_queries_sent;
|
||||||
|
unsigned char multicast_router;
|
||||||
|
struct timer_list multicast_router_timer;
|
||||||
|
struct timer_list multicast_query_timer;
|
||||||
|
struct hlist_head mglist;
|
||||||
|
struct hlist_node rlist;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
struct net_bridge
|
struct net_bridge
|
||||||
|
@ -124,6 +168,35 @@ struct net_bridge
|
||||||
unsigned char topology_change;
|
unsigned char topology_change;
|
||||||
unsigned char topology_change_detected;
|
unsigned char topology_change_detected;
|
||||||
|
|
||||||
|
#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
|
||||||
|
unsigned char multicast_router;
|
||||||
|
|
||||||
|
u8 multicast_disabled:1;
|
||||||
|
|
||||||
|
u32 hash_elasticity;
|
||||||
|
u32 hash_max;
|
||||||
|
|
||||||
|
u32 multicast_last_member_count;
|
||||||
|
u32 multicast_startup_queries_sent;
|
||||||
|
u32 multicast_startup_query_count;
|
||||||
|
|
||||||
|
unsigned long multicast_last_member_interval;
|
||||||
|
unsigned long multicast_membership_interval;
|
||||||
|
unsigned long multicast_querier_interval;
|
||||||
|
unsigned long multicast_query_interval;
|
||||||
|
unsigned long multicast_query_response_interval;
|
||||||
|
unsigned long multicast_startup_query_interval;
|
||||||
|
|
||||||
|
spinlock_t multicast_lock;
|
||||||
|
struct net_bridge_mdb_htable *mdb;
|
||||||
|
struct hlist_head router_list;
|
||||||
|
struct hlist_head mglist;
|
||||||
|
|
||||||
|
struct timer_list multicast_router_timer;
|
||||||
|
struct timer_list multicast_querier_timer;
|
||||||
|
struct timer_list multicast_query_timer;
|
||||||
|
#endif
|
||||||
|
|
||||||
struct timer_list hello_timer;
|
struct timer_list hello_timer;
|
||||||
struct timer_list tcn_timer;
|
struct timer_list tcn_timer;
|
||||||
struct timer_list topology_change_timer;
|
struct timer_list topology_change_timer;
|
||||||
|
@ -133,6 +206,8 @@ struct net_bridge
|
||||||
|
|
||||||
struct br_input_skb_cb {
|
struct br_input_skb_cb {
|
||||||
struct net_device *brdev;
|
struct net_device *brdev;
|
||||||
|
int igmp;
|
||||||
|
int mrouters_only;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define BR_INPUT_SKB_CB(__skb) ((struct br_input_skb_cb *)(__skb)->cb)
|
#define BR_INPUT_SKB_CB(__skb) ((struct br_input_skb_cb *)(__skb)->cb)
|
||||||
|
@ -204,6 +279,70 @@ extern struct sk_buff *br_handle_frame(struct net_bridge_port *p,
|
||||||
extern int br_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
|
extern int br_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
|
||||||
extern int br_ioctl_deviceless_stub(struct net *net, unsigned int cmd, void __user *arg);
|
extern int br_ioctl_deviceless_stub(struct net *net, unsigned int cmd, void __user *arg);
|
||||||
|
|
||||||
|
/* br_multicast.c */
|
||||||
|
#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
|
||||||
|
extern int br_multicast_rcv(struct net_bridge *br,
|
||||||
|
struct net_bridge_port *port,
|
||||||
|
struct sk_buff *skb);
|
||||||
|
extern struct net_bridge_mdb_entry *br_mdb_get(struct net_bridge *br,
|
||||||
|
struct sk_buff *skb);
|
||||||
|
extern void br_multicast_add_port(struct net_bridge_port *port);
|
||||||
|
extern void br_multicast_del_port(struct net_bridge_port *port);
|
||||||
|
extern void br_multicast_enable_port(struct net_bridge_port *port);
|
||||||
|
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);
|
||||||
|
#else
|
||||||
|
static inline int br_multicast_rcv(struct net_bridge *br,
|
||||||
|
struct net_bridge_port *port,
|
||||||
|
struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct net_bridge_mdb_entry *br_mdb_get(struct net_bridge *br,
|
||||||
|
struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void br_multicast_add_port(struct net_bridge_port *port)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void br_multicast_del_port(struct net_bridge_port *port)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void br_multicast_enable_port(struct net_bridge_port *port)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void br_multicast_disable_port(struct net_bridge_port *port)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void br_multicast_init(struct net_bridge *br)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void br_multicast_open(struct net_bridge *br)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void br_multicast_stop(struct net_bridge *br)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static inline bool br_multicast_is_router(struct net_bridge *br)
|
||||||
|
{
|
||||||
|
return br->multicast_router == 2 ||
|
||||||
|
(br->multicast_router == 1 &&
|
||||||
|
timer_pending(&br->multicast_router_timer));
|
||||||
|
}
|
||||||
|
|
||||||
/* br_netfilter.c */
|
/* br_netfilter.c */
|
||||||
#ifdef CONFIG_BRIDGE_NETFILTER
|
#ifdef CONFIG_BRIDGE_NETFILTER
|
||||||
extern int br_netfilter_init(void);
|
extern int br_netfilter_init(void);
|
||||||
|
|
Loading…
Reference in a new issue