bridge: Add multicast_router sysfs entries
This patch allows the user to forcibly enable/disable ports as having multicast routers attached. A port with a multicast router will receive all multicast traffic. The value 0 disables it completely. The default is 1 which lets the system automatically detect the presence of routers (currently this is limited to picking up queries), and 2 means that the port will always receive all multicast traffic. 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
c4fcb78cf8
commit
0909e11758
|
@ -746,12 +746,30 @@ static int br_multicast_igmp3_report(struct net_bridge *br,
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void br_multicast_add_router(struct net_bridge *br,
|
||||||
|
struct net_bridge_port *port)
|
||||||
|
{
|
||||||
|
struct hlist_node *p;
|
||||||
|
struct hlist_node **h;
|
||||||
|
|
||||||
|
for (h = &br->router_list.first;
|
||||||
|
(p = *h) &&
|
||||||
|
(unsigned long)container_of(p, struct net_bridge_port, rlist) >
|
||||||
|
(unsigned long)port;
|
||||||
|
h = &p->next)
|
||||||
|
;
|
||||||
|
|
||||||
|
port->rlist.pprev = h;
|
||||||
|
port->rlist.next = p;
|
||||||
|
rcu_assign_pointer(*h, &port->rlist);
|
||||||
|
if (p)
|
||||||
|
p->pprev = &port->rlist.next;
|
||||||
|
}
|
||||||
|
|
||||||
static void br_multicast_mark_router(struct net_bridge *br,
|
static void br_multicast_mark_router(struct net_bridge *br,
|
||||||
struct net_bridge_port *port)
|
struct net_bridge_port *port)
|
||||||
{
|
{
|
||||||
unsigned long now = jiffies;
|
unsigned long now = jiffies;
|
||||||
struct hlist_node *p;
|
|
||||||
struct hlist_node **h;
|
|
||||||
|
|
||||||
if (!port) {
|
if (!port) {
|
||||||
if (br->multicast_router == 1)
|
if (br->multicast_router == 1)
|
||||||
|
@ -766,18 +784,7 @@ static void br_multicast_mark_router(struct net_bridge *br,
|
||||||
if (!hlist_unhashed(&port->rlist))
|
if (!hlist_unhashed(&port->rlist))
|
||||||
goto timer;
|
goto timer;
|
||||||
|
|
||||||
for (h = &br->router_list.first;
|
br_multicast_add_router(br, port);
|
||||||
(p = *h) &&
|
|
||||||
(unsigned long)container_of(p, struct net_bridge_port, rlist) >
|
|
||||||
(unsigned long)port;
|
|
||||||
h = &p->next)
|
|
||||||
;
|
|
||||||
|
|
||||||
port->rlist.pprev = h;
|
|
||||||
port->rlist.next = p;
|
|
||||||
rcu_assign_pointer(*h, &port->rlist);
|
|
||||||
if (p)
|
|
||||||
p->pprev = &port->rlist.next;
|
|
||||||
|
|
||||||
timer:
|
timer:
|
||||||
mod_timer(&port->multicast_router_timer,
|
mod_timer(&port->multicast_router_timer,
|
||||||
|
@ -1133,3 +1140,73 @@ void br_multicast_stop(struct net_bridge *br)
|
||||||
out:
|
out:
|
||||||
spin_unlock_bh(&br->multicast_lock);
|
spin_unlock_bh(&br->multicast_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int br_multicast_set_router(struct net_bridge *br, unsigned long val)
|
||||||
|
{
|
||||||
|
int err = -ENOENT;
|
||||||
|
|
||||||
|
spin_lock_bh(&br->multicast_lock);
|
||||||
|
if (!netif_running(br->dev))
|
||||||
|
goto unlock;
|
||||||
|
|
||||||
|
switch (val) {
|
||||||
|
case 0:
|
||||||
|
case 2:
|
||||||
|
del_timer(&br->multicast_router_timer);
|
||||||
|
/* fall through */
|
||||||
|
case 1:
|
||||||
|
br->multicast_router = val;
|
||||||
|
err = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
err = -EINVAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
unlock:
|
||||||
|
spin_unlock_bh(&br->multicast_lock);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
int br_multicast_set_port_router(struct net_bridge_port *p, unsigned long val)
|
||||||
|
{
|
||||||
|
struct net_bridge *br = p->br;
|
||||||
|
int err = -ENOENT;
|
||||||
|
|
||||||
|
spin_lock(&br->multicast_lock);
|
||||||
|
if (!netif_running(br->dev) || p->state == BR_STATE_DISABLED)
|
||||||
|
goto unlock;
|
||||||
|
|
||||||
|
switch (val) {
|
||||||
|
case 0:
|
||||||
|
case 1:
|
||||||
|
case 2:
|
||||||
|
p->multicast_router = val;
|
||||||
|
err = 0;
|
||||||
|
|
||||||
|
if (val < 2 && !hlist_unhashed(&p->rlist))
|
||||||
|
hlist_del_init_rcu(&p->rlist);
|
||||||
|
|
||||||
|
if (val == 1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
del_timer(&p->multicast_router_timer);
|
||||||
|
|
||||||
|
if (val == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
br_multicast_add_router(br, p);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
err = -EINVAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
unlock:
|
||||||
|
spin_unlock(&br->multicast_lock);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
|
@ -297,6 +297,9 @@ extern void br_multicast_deliver(struct net_bridge_mdb_entry *mdst,
|
||||||
struct sk_buff *skb);
|
struct sk_buff *skb);
|
||||||
extern void br_multicast_forward(struct net_bridge_mdb_entry *mdst,
|
extern void br_multicast_forward(struct net_bridge_mdb_entry *mdst,
|
||||||
struct sk_buff *skb, struct sk_buff *skb2);
|
struct sk_buff *skb, struct sk_buff *skb2);
|
||||||
|
extern int br_multicast_set_router(struct net_bridge *br, unsigned long val);
|
||||||
|
extern int br_multicast_set_port_router(struct net_bridge_port *p,
|
||||||
|
unsigned long val);
|
||||||
#else
|
#else
|
||||||
static inline int br_multicast_rcv(struct net_bridge *br,
|
static inline int br_multicast_rcv(struct net_bridge *br,
|
||||||
struct net_bridge_port *port,
|
struct net_bridge_port *port,
|
||||||
|
|
|
@ -345,6 +345,24 @@ static ssize_t store_flush(struct device *d,
|
||||||
}
|
}
|
||||||
static DEVICE_ATTR(flush, S_IWUSR, NULL, store_flush);
|
static DEVICE_ATTR(flush, S_IWUSR, NULL, store_flush);
|
||||||
|
|
||||||
|
#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
|
||||||
|
static ssize_t show_multicast_router(struct device *d,
|
||||||
|
struct device_attribute *attr, char *buf)
|
||||||
|
{
|
||||||
|
struct net_bridge *br = to_bridge(d);
|
||||||
|
return sprintf(buf, "%d\n", br->multicast_router);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t store_multicast_router(struct device *d,
|
||||||
|
struct device_attribute *attr,
|
||||||
|
const char *buf, size_t len)
|
||||||
|
{
|
||||||
|
return store_bridge_parm(d, buf, len, br_multicast_set_router);
|
||||||
|
}
|
||||||
|
static DEVICE_ATTR(multicast_router, S_IRUGO | S_IWUSR, show_multicast_router,
|
||||||
|
store_multicast_router);
|
||||||
|
#endif
|
||||||
|
|
||||||
static struct attribute *bridge_attrs[] = {
|
static struct attribute *bridge_attrs[] = {
|
||||||
&dev_attr_forward_delay.attr,
|
&dev_attr_forward_delay.attr,
|
||||||
&dev_attr_hello_time.attr,
|
&dev_attr_hello_time.attr,
|
||||||
|
@ -364,6 +382,9 @@ static struct attribute *bridge_attrs[] = {
|
||||||
&dev_attr_gc_timer.attr,
|
&dev_attr_gc_timer.attr,
|
||||||
&dev_attr_group_addr.attr,
|
&dev_attr_group_addr.attr,
|
||||||
&dev_attr_flush.attr,
|
&dev_attr_flush.attr,
|
||||||
|
#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
|
||||||
|
&dev_attr_multicast_router.attr,
|
||||||
|
#endif
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -159,6 +159,21 @@ static ssize_t store_hairpin_mode(struct net_bridge_port *p, unsigned long v)
|
||||||
static BRPORT_ATTR(hairpin_mode, S_IRUGO | S_IWUSR,
|
static BRPORT_ATTR(hairpin_mode, S_IRUGO | S_IWUSR,
|
||||||
show_hairpin_mode, store_hairpin_mode);
|
show_hairpin_mode, store_hairpin_mode);
|
||||||
|
|
||||||
|
#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
|
||||||
|
static ssize_t show_multicast_router(struct net_bridge_port *p, char *buf)
|
||||||
|
{
|
||||||
|
return sprintf(buf, "%d\n", p->multicast_router);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t store_multicast_router(struct net_bridge_port *p,
|
||||||
|
unsigned long v)
|
||||||
|
{
|
||||||
|
return br_multicast_set_port_router(p, v);
|
||||||
|
}
|
||||||
|
static BRPORT_ATTR(multicast_router, S_IRUGO | S_IWUSR, show_multicast_router,
|
||||||
|
store_multicast_router);
|
||||||
|
#endif
|
||||||
|
|
||||||
static struct brport_attribute *brport_attrs[] = {
|
static struct brport_attribute *brport_attrs[] = {
|
||||||
&brport_attr_path_cost,
|
&brport_attr_path_cost,
|
||||||
&brport_attr_priority,
|
&brport_attr_priority,
|
||||||
|
@ -176,6 +191,9 @@ static struct brport_attribute *brport_attrs[] = {
|
||||||
&brport_attr_hold_timer,
|
&brport_attr_hold_timer,
|
||||||
&brport_attr_flush,
|
&brport_attr_flush,
|
||||||
&brport_attr_hairpin_mode,
|
&brport_attr_hairpin_mode,
|
||||||
|
#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
|
||||||
|
&brport_attr_multicast_router,
|
||||||
|
#endif
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue