@@ -161,7 +161,10 @@ enum {
* }
* }
* [MDBA_ROUTER] = {
- * [MDBA_ROUTER_PORT]
+ * [MDBA_ROUTER_PORT] = {
+ * u32 ifindex
+ * [MDBA_ROUTER_PATTR attributes]
+ * }
* }
*/
enum {
@@ -199,6 +202,7 @@ enum {
MDB_RTR_TYPE_DISABLED,
MDB_RTR_TYPE_TEMP_QUERY,
MDB_RTR_TYPE_PERM,
+ MDB_RTR_TYPE_TEMP
};
enum {
@@ -208,6 +212,15 @@ enum {
};
#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 {
__u8 family;
__u32 ifindex;
@@ -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_port *p;
- struct nlattr *nest;
+ struct nlattr *nest, *port_nest;
if (!br->multicast_router || hlist_empty(&br->router_list))
return 0;
@@ -30,8 +30,20 @@ static int br_rports_fill_info(struct sk_buff *skb, struct netlink_callback *cb,
return -EMSGSIZE;
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;
+ 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);
@@ -759,13 +759,17 @@ static void br_multicast_router_expired(unsigned long data)
struct net_bridge *br = port->br;
spin_lock(&br->multicast_lock);
- if (port->multicast_router != MDB_RTR_TYPE_TEMP_QUERY ||
+ if (port->multicast_router == MDB_RTR_TYPE_DISABLED ||
+ port->multicast_router == MDB_RTR_TYPE_PERM ||
timer_pending(&port->multicast_router_timer) ||
hlist_unhashed(&port->rlist))
goto out;
hlist_del_init_rcu(&port->rlist);
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:
spin_unlock(&br->multicast_lock);
@@ -981,6 +985,9 @@ void br_multicast_disable_port(struct net_bridge_port *port)
if (!hlist_unhashed(&port->rlist)) {
hlist_del_init_rcu(&port->rlist);
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->ip4_own_query.timer);
@@ -1234,7 +1241,8 @@ static void br_multicast_mark_router(struct net_bridge *br,
return;
}
- if (port->multicast_router != MDB_RTR_TYPE_TEMP_QUERY)
+ if (port->multicast_router == MDB_RTR_TYPE_DISABLED ||
+ port->multicast_router == MDB_RTR_TYPE_PERM)
return;
br_multicast_add_router(br, port);
@@ -1850,10 +1858,15 @@ static void __del_port_router(struct net_bridge_port *p)
int br_multicast_set_port_router(struct net_bridge_port *p, unsigned long val)
{
struct net_bridge *br = p->br;
+ unsigned long now = jiffies;
int err = -EINVAL;
spin_lock(&br->multicast_lock);
if (p->multicast_router == val) {
+ /* Refresh the temp router port timer */
+ if (p->multicast_router == MDB_RTR_TYPE_TEMP)
+ mod_timer(&p->multicast_router_timer,
+ now + br->multicast_querier_interval);
err = 0;
goto unlock;
}
@@ -1869,6 +1882,9 @@ int br_multicast_set_port_router(struct net_bridge_port *p, unsigned long val)
del_timer(&p->multicast_router_timer);
br_multicast_add_router(br, p);
break;
+ case MDB_RTR_TYPE_TEMP:
+ br_multicast_mark_router(br, p);
+ break;
default:
goto unlock;
}
Add support for a temporary router port which doesn't depend on the incoming query and allow for more port information to be dumped. For that purpose we need to extend the MDBA_ROUTER_PORT attribute similar to how it was done for the mdb entries recently. The new format is thus: [MDBA_ROUTER_PORT] = { <- nested attribute u32 ifindex <- router port ifindex for user-space compatibility [MDBA_ROUTER_PATTR attributes] } This way it remains compatible with older users (they'll simply retrieve the u32 in the beginning) and new users can parse the remaining attributes. Signed-off-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com> --- include/uapi/linux/if_bridge.h | 15 ++++++++++++++- net/bridge/br_mdb.c | 16 ++++++++++++++-- net/bridge/br_multicast.c | 20 ++++++++++++++++++-- 3 files changed, 46 insertions(+), 5 deletions(-)