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:
committed by
David S. Miller
parent
c4fcb78cf8
commit
0909e11758
@ -746,12 +746,30 @@ static int br_multicast_igmp3_report(struct net_bridge *br,
|
||||
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,
|
||||
struct net_bridge_port *port)
|
||||
{
|
||||
unsigned long now = jiffies;
|
||||
struct hlist_node *p;
|
||||
struct hlist_node **h;
|
||||
|
||||
if (!port) {
|
||||
if (br->multicast_router == 1)
|
||||
@ -766,18 +784,7 @@ static void br_multicast_mark_router(struct net_bridge *br,
|
||||
if (!hlist_unhashed(&port->rlist))
|
||||
goto timer;
|
||||
|
||||
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;
|
||||
br_multicast_add_router(br, port);
|
||||
|
||||
timer:
|
||||
mod_timer(&port->multicast_router_timer,
|
||||
@ -1133,3 +1140,73 @@ void br_multicast_stop(struct net_bridge *br)
|
||||
out:
|
||||
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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user