OSDN Git Service

net: bridge: mcast: use the proper multicast context when dumping router ports
authorNikolay Aleksandrov <nikolay@nvidia.com>
Tue, 10 Aug 2021 15:29:32 +0000 (18:29 +0300)
committerDavid S. Miller <davem@davemloft.net>
Wed, 11 Aug 2021 12:34:41 +0000 (13:34 +0100)
When we are dumping the router ports of a vlan mcast context we need to
use the bridge/vlan and port/vlan's multicast contexts to check if
IPv4/IPv6 router port is present and later to dump the vlan id.

Signed-off-by: Nikolay Aleksandrov <nikolay@nvidia.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/bridge/br_mdb.c

index 73a8915..7c16e2c 100644 (file)
@@ -16,7 +16,7 @@
 
 #include "br_private.h"
 
-static bool br_rports_have_mc_router(struct net_bridge_mcast *brmctx)
+static bool br_rports_have_mc_router(const struct net_bridge_mcast *brmctx)
 {
 #if IS_ENABLED(CONFIG_IPV6)
        return !hlist_empty(&brmctx->ip4_mc_router_list) ||
@@ -27,46 +27,58 @@ static bool br_rports_have_mc_router(struct net_bridge_mcast *brmctx)
 }
 
 static bool
-br_ip4_rports_get_timer(struct net_bridge_port *port, unsigned long *timer)
+br_ip4_rports_get_timer(struct net_bridge_mcast_port *pmctx,
+                       unsigned long *timer)
 {
-       *timer = br_timer_value(&port->multicast_ctx.ip4_mc_router_timer);
-       return !hlist_unhashed(&port->multicast_ctx.ip4_rlist);
+       *timer = br_timer_value(&pmctx->ip4_mc_router_timer);
+       return !hlist_unhashed(&pmctx->ip4_rlist);
 }
 
 static bool
-br_ip6_rports_get_timer(struct net_bridge_port *port, unsigned long *timer)
+br_ip6_rports_get_timer(struct net_bridge_mcast_port *pmctx,
+                       unsigned long *timer)
 {
 #if IS_ENABLED(CONFIG_IPV6)
-       *timer = br_timer_value(&port->multicast_ctx.ip6_mc_router_timer);
-       return !hlist_unhashed(&port->multicast_ctx.ip6_rlist);
+       *timer = br_timer_value(&pmctx->ip6_mc_router_timer);
+       return !hlist_unhashed(&pmctx->ip6_rlist);
 #else
        *timer = 0;
        return false;
 #endif
 }
 
-static int br_rports_fill_info(struct sk_buff *skb, struct netlink_callback *cb,
-                              struct net_device *dev)
+static int br_rports_fill_info(struct sk_buff *skb,
+                              const struct net_bridge_mcast *brmctx)
 {
-       struct net_bridge *br = netdev_priv(dev);
+       u16 vid = brmctx->vlan ? brmctx->vlan->vid : 0;
        bool have_ip4_mc_rtr, have_ip6_mc_rtr;
        unsigned long ip4_timer, ip6_timer;
        struct nlattr *nest, *port_nest;
        struct net_bridge_port *p;
 
-       if (!br->multicast_ctx.multicast_router)
-               return 0;
-
-       if (!br_rports_have_mc_router(&br->multicast_ctx))
+       if (!brmctx->multicast_router || !br_rports_have_mc_router(brmctx))
                return 0;
 
        nest = nla_nest_start_noflag(skb, MDBA_ROUTER);
        if (nest == NULL)
                return -EMSGSIZE;
 
-       list_for_each_entry_rcu(p, &br->port_list, list) {
-               have_ip4_mc_rtr = br_ip4_rports_get_timer(p, &ip4_timer);
-               have_ip6_mc_rtr = br_ip6_rports_get_timer(p, &ip6_timer);
+       list_for_each_entry_rcu(p, &brmctx->br->port_list, list) {
+               struct net_bridge_mcast_port *pmctx;
+
+               if (vid) {
+                       struct net_bridge_vlan *v;
+
+                       v = br_vlan_find(nbp_vlan_group(p), vid);
+                       if (!v)
+                               continue;
+                       pmctx = &v->port_mcast_ctx;
+               } else {
+                       pmctx = &p->multicast_ctx;
+               }
+
+               have_ip4_mc_rtr = br_ip4_rports_get_timer(pmctx, &ip4_timer);
+               have_ip6_mc_rtr = br_ip6_rports_get_timer(pmctx, &ip6_timer);
 
                if (!have_ip4_mc_rtr && !have_ip6_mc_rtr)
                        continue;
@@ -390,6 +402,7 @@ static int br_mdb_dump(struct sk_buff *skb, struct netlink_callback *cb)
 
        for_each_netdev_rcu(net, dev) {
                if (dev->priv_flags & IFF_EBRIDGE) {
+                       struct net_bridge *br = netdev_priv(dev);
                        struct br_port_msg *bpm;
 
                        if (idx < s_idx)
@@ -406,7 +419,7 @@ static int br_mdb_dump(struct sk_buff *skb, struct netlink_callback *cb)
                        bpm->ifindex = dev->ifindex;
                        if (br_mdb_fill_info(skb, cb, dev) < 0)
                                goto out;
-                       if (br_rports_fill_info(skb, cb, dev) < 0)
+                       if (br_rports_fill_info(skb, &br->multicast_ctx) < 0)
                                goto out;
 
                        cb->args[1] = 0;