Commit 4ec62070 authored by David S. Miller's avatar David S. Miller

Merge branch 'bridge-mcast-tmp-router-port'

Nikolay Aleksandrov says:

====================
bridge: mcast: add support for temp router port

This set adds support for temporary router port which doesn't depend only
on the incoming queries. It can be refreshed by setting multicast_router to
the same value (3). The first two patches are minor changes that prepare
the code for the third which adds this new type of router port.
In order to be able to dump its information the mdb router port format
is changed in patch 04 and extended similar to how mdb entries format was
done recently.
The related iproute2 changes will be posted if this is accepted.

v2: set val first and adjust router type later in patch 01, patch 03 was
split in 2
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents ec1606c0 59f78f9f
...@@ -144,7 +144,10 @@ struct bridge_vlan_info { ...@@ -144,7 +144,10 @@ struct bridge_vlan_info {
* } * }
* } * }
* [MDBA_ROUTER] = { * [MDBA_ROUTER] = {
* [MDBA_ROUTER_PORT] * [MDBA_ROUTER_PORT] = {
* u32 ifindex
* [MDBA_ROUTER_PATTR attributes]
* }
* } * }
*/ */
enum { enum {
...@@ -177,6 +180,14 @@ enum { ...@@ -177,6 +180,14 @@ enum {
}; };
#define MDBA_MDB_EATTR_MAX (__MDBA_MDB_EATTR_MAX - 1) #define MDBA_MDB_EATTR_MAX (__MDBA_MDB_EATTR_MAX - 1)
/* multicast router types */
enum {
MDB_RTR_TYPE_DISABLED,
MDB_RTR_TYPE_TEMP_QUERY,
MDB_RTR_TYPE_PERM,
MDB_RTR_TYPE_TEMP
};
enum { enum {
MDBA_ROUTER_UNSPEC, MDBA_ROUTER_UNSPEC,
MDBA_ROUTER_PORT, MDBA_ROUTER_PORT,
...@@ -184,6 +195,15 @@ enum { ...@@ -184,6 +195,15 @@ enum {
}; };
#define MDBA_ROUTER_MAX (__MDBA_ROUTER_MAX - 1) #define MDBA_ROUTER_MAX (__MDBA_ROUTER_MAX - 1)
/* router port attributes */
enum {
MDBA_ROUTER_PATTR_UNSPEC,
MDBA_ROUTER_PATTR_TIMER,
MDBA_ROUTER_PATTR_TYPE,
__MDBA_ROUTER_PATTR_MAX
};
#define MDBA_ROUTER_PATTR_MAX (__MDBA_ROUTER_PATTR_MAX - 1)
struct br_port_msg { struct br_port_msg {
__u8 family; __u8 family;
__u32 ifindex; __u32 ifindex;
......
...@@ -20,7 +20,7 @@ static int br_rports_fill_info(struct sk_buff *skb, struct netlink_callback *cb, ...@@ -20,7 +20,7 @@ static int br_rports_fill_info(struct sk_buff *skb, struct netlink_callback *cb,
{ {
struct net_bridge *br = netdev_priv(dev); struct net_bridge *br = netdev_priv(dev);
struct net_bridge_port *p; struct net_bridge_port *p;
struct nlattr *nest; struct nlattr *nest, *port_nest;
if (!br->multicast_router || hlist_empty(&br->router_list)) if (!br->multicast_router || hlist_empty(&br->router_list))
return 0; return 0;
...@@ -30,8 +30,20 @@ static int br_rports_fill_info(struct sk_buff *skb, struct netlink_callback *cb, ...@@ -30,8 +30,20 @@ static int br_rports_fill_info(struct sk_buff *skb, struct netlink_callback *cb,
return -EMSGSIZE; return -EMSGSIZE;
hlist_for_each_entry_rcu(p, &br->router_list, rlist) { hlist_for_each_entry_rcu(p, &br->router_list, rlist) {
if (p && nla_put_u32(skb, MDBA_ROUTER_PORT, p->dev->ifindex)) if (!p)
continue;
port_nest = nla_nest_start(skb, MDBA_ROUTER_PORT);
if (!port_nest)
goto fail; goto fail;
if (nla_put_nohdr(skb, sizeof(u32), &p->dev->ifindex) ||
nla_put_u32(skb, MDBA_ROUTER_PATTR_TIMER,
br_timer_value(&p->multicast_router_timer)) ||
nla_put_u8(skb, MDBA_ROUTER_PATTR_TYPE,
p->multicast_router)) {
nla_nest_cancel(skb, port_nest);
goto fail;
}
nla_nest_end(skb, port_nest);
} }
nla_nest_end(skb, nest); nla_nest_end(skb, nest);
......
...@@ -759,13 +759,17 @@ static void br_multicast_router_expired(unsigned long data) ...@@ -759,13 +759,17 @@ static void br_multicast_router_expired(unsigned long data)
struct net_bridge *br = port->br; struct net_bridge *br = port->br;
spin_lock(&br->multicast_lock); spin_lock(&br->multicast_lock);
if (port->multicast_router != 1 || if (port->multicast_router == MDB_RTR_TYPE_DISABLED ||
port->multicast_router == MDB_RTR_TYPE_PERM ||
timer_pending(&port->multicast_router_timer) || timer_pending(&port->multicast_router_timer) ||
hlist_unhashed(&port->rlist)) hlist_unhashed(&port->rlist))
goto out; goto out;
hlist_del_init_rcu(&port->rlist); hlist_del_init_rcu(&port->rlist);
br_rtr_notify(br->dev, port, RTM_DELMDB); br_rtr_notify(br->dev, port, RTM_DELMDB);
/* Don't allow timer refresh if the router expired */
if (port->multicast_router == MDB_RTR_TYPE_TEMP)
port->multicast_router = MDB_RTR_TYPE_TEMP_QUERY;
out: out:
spin_unlock(&br->multicast_lock); spin_unlock(&br->multicast_lock);
...@@ -912,7 +916,7 @@ static void br_ip6_multicast_port_query_expired(unsigned long data) ...@@ -912,7 +916,7 @@ static void br_ip6_multicast_port_query_expired(unsigned long data)
void br_multicast_add_port(struct net_bridge_port *port) void br_multicast_add_port(struct net_bridge_port *port)
{ {
port->multicast_router = 1; port->multicast_router = MDB_RTR_TYPE_TEMP_QUERY;
setup_timer(&port->multicast_router_timer, br_multicast_router_expired, setup_timer(&port->multicast_router_timer, br_multicast_router_expired,
(unsigned long)port); (unsigned long)port);
...@@ -959,7 +963,8 @@ void br_multicast_enable_port(struct net_bridge_port *port) ...@@ -959,7 +963,8 @@ void br_multicast_enable_port(struct net_bridge_port *port)
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)
br_multicast_enable(&port->ip6_own_query); br_multicast_enable(&port->ip6_own_query);
#endif #endif
if (port->multicast_router == 2 && hlist_unhashed(&port->rlist)) if (port->multicast_router == MDB_RTR_TYPE_PERM &&
hlist_unhashed(&port->rlist))
br_multicast_add_router(br, port); br_multicast_add_router(br, port);
out: out:
...@@ -980,6 +985,9 @@ void br_multicast_disable_port(struct net_bridge_port *port) ...@@ -980,6 +985,9 @@ void br_multicast_disable_port(struct net_bridge_port *port)
if (!hlist_unhashed(&port->rlist)) { if (!hlist_unhashed(&port->rlist)) {
hlist_del_init_rcu(&port->rlist); hlist_del_init_rcu(&port->rlist);
br_rtr_notify(br->dev, port, RTM_DELMDB); br_rtr_notify(br->dev, port, RTM_DELMDB);
/* Don't allow timer refresh if disabling */
if (port->multicast_router == MDB_RTR_TYPE_TEMP)
port->multicast_router = MDB_RTR_TYPE_TEMP_QUERY;
} }
del_timer(&port->multicast_router_timer); del_timer(&port->multicast_router_timer);
del_timer(&port->ip4_own_query.timer); del_timer(&port->ip4_own_query.timer);
...@@ -1227,13 +1235,14 @@ static void br_multicast_mark_router(struct net_bridge *br, ...@@ -1227,13 +1235,14 @@ static void br_multicast_mark_router(struct net_bridge *br,
unsigned long now = jiffies; unsigned long now = jiffies;
if (!port) { if (!port) {
if (br->multicast_router == 1) if (br->multicast_router == MDB_RTR_TYPE_TEMP_QUERY)
mod_timer(&br->multicast_router_timer, mod_timer(&br->multicast_router_timer,
now + br->multicast_querier_interval); now + br->multicast_querier_interval);
return; return;
} }
if (port->multicast_router != 1) if (port->multicast_router == MDB_RTR_TYPE_DISABLED ||
port->multicast_router == MDB_RTR_TYPE_PERM)
return; return;
br_multicast_add_router(br, port); br_multicast_add_router(br, port);
...@@ -1713,7 +1722,7 @@ void br_multicast_init(struct net_bridge *br) ...@@ -1713,7 +1722,7 @@ void br_multicast_init(struct net_bridge *br)
br->hash_elasticity = 4; br->hash_elasticity = 4;
br->hash_max = 512; br->hash_max = 512;
br->multicast_router = 1; br->multicast_router = MDB_RTR_TYPE_TEMP_QUERY;
br->multicast_querier = 0; br->multicast_querier = 0;
br->multicast_query_use_ifaddr = 0; br->multicast_query_use_ifaddr = 0;
br->multicast_last_member_count = 2; br->multicast_last_member_count = 2;
...@@ -1823,11 +1832,11 @@ int br_multicast_set_router(struct net_bridge *br, unsigned long val) ...@@ -1823,11 +1832,11 @@ int br_multicast_set_router(struct net_bridge *br, unsigned long val)
spin_lock_bh(&br->multicast_lock); spin_lock_bh(&br->multicast_lock);
switch (val) { switch (val) {
case 0: case MDB_RTR_TYPE_DISABLED:
case 2: case MDB_RTR_TYPE_PERM:
del_timer(&br->multicast_router_timer); del_timer(&br->multicast_router_timer);
/* fall through */ /* fall through */
case 1: case MDB_RTR_TYPE_TEMP_QUERY:
br->multicast_router = val; br->multicast_router = val;
err = 0; err = 0;
break; break;
...@@ -1838,37 +1847,53 @@ int br_multicast_set_router(struct net_bridge *br, unsigned long val) ...@@ -1838,37 +1847,53 @@ int br_multicast_set_router(struct net_bridge *br, unsigned long val)
return err; return err;
} }
static void __del_port_router(struct net_bridge_port *p)
{
if (hlist_unhashed(&p->rlist))
return;
hlist_del_init_rcu(&p->rlist);
br_rtr_notify(p->br->dev, p, RTM_DELMDB);
}
int br_multicast_set_port_router(struct net_bridge_port *p, unsigned long val) int br_multicast_set_port_router(struct net_bridge_port *p, unsigned long val)
{ {
struct net_bridge *br = p->br; struct net_bridge *br = p->br;
unsigned long now = jiffies;
int err = -EINVAL; int err = -EINVAL;
spin_lock(&br->multicast_lock); spin_lock(&br->multicast_lock);
if (p->multicast_router == val) {
switch (val) { /* Refresh the temp router port timer */
case 0: if (p->multicast_router == MDB_RTR_TYPE_TEMP)
case 1: mod_timer(&p->multicast_router_timer,
case 2: now + br->multicast_querier_interval);
p->multicast_router = val;
err = 0; err = 0;
goto unlock;
if (val < 2 && !hlist_unhashed(&p->rlist)) {
hlist_del_init_rcu(&p->rlist);
br_rtr_notify(br->dev, p, RTM_DELMDB);
} }
switch (val) {
if (val == 1) case MDB_RTR_TYPE_DISABLED:
break; p->multicast_router = MDB_RTR_TYPE_DISABLED;
__del_port_router(p);
del_timer(&p->multicast_router_timer); del_timer(&p->multicast_router_timer);
if (val == 0)
break; break;
case MDB_RTR_TYPE_TEMP_QUERY:
p->multicast_router = MDB_RTR_TYPE_TEMP_QUERY;
__del_port_router(p);
break;
case MDB_RTR_TYPE_PERM:
p->multicast_router = MDB_RTR_TYPE_PERM;
del_timer(&p->multicast_router_timer);
br_multicast_add_router(br, p); br_multicast_add_router(br, p);
break; break;
case MDB_RTR_TYPE_TEMP:
p->multicast_router = MDB_RTR_TYPE_TEMP;
br_multicast_mark_router(br, p);
break;
default:
goto unlock;
} }
err = 0;
unlock:
spin_unlock(&br->multicast_lock); spin_unlock(&br->multicast_lock);
return err; return err;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment