net: bridge: mcast: record querier port device ifindex instead of pointer
authorNikolay Aleksandrov <nikolay@nvidia.com>
Fri, 13 Aug 2021 14:59:57 +0000 (17:59 +0300)
committerDavid S. Miller <davem@davemloft.net>
Sat, 14 Aug 2021 13:02:43 +0000 (14:02 +0100)
Currently when a querier port is detected its net_bridge_port pointer is
recorded, but it's used only for comparisons so it's fine to have stale
pointer, in order to dereference and use the port pointer a proper
accounting of its usage must be implemented adding unnecessary
complexity. To solve the problem we can just store the netdevice ifindex
instead of the port pointer and retrieve the bridge port. It is a best
effort and the device needs to be validated that is still part of that
bridge before use, but that is small price to pay for avoiding querier
reference counting for each port/vlan.

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

index df6bf6a237aa4fdc4376366d879ffee53dc0930e..853b947edf871904dd8e3c292bdb3a6da32b4d2d 100644 (file)
@@ -2850,7 +2850,8 @@ update:
        brmctx->ip4_querier.addr.src.ip4 = saddr;
 
        /* update protected by general multicast_lock by caller */
-       rcu_assign_pointer(brmctx->ip4_querier.port, port);
+       if (port)
+               brmctx->ip4_querier.port_ifidx = port->dev->ifindex;
 
        return true;
 }
@@ -2875,7 +2876,8 @@ update:
        brmctx->ip6_querier.addr.src.ip6 = *saddr;
 
        /* update protected by general multicast_lock by caller */
-       rcu_assign_pointer(brmctx->ip6_querier.port, port);
+       if (port)
+               brmctx->ip6_querier.port_ifidx = port->dev->ifindex;
 
        return true;
 }
@@ -3675,7 +3677,7 @@ static void br_multicast_query_expired(struct net_bridge_mcast *brmctx,
        if (query->startup_sent < brmctx->multicast_startup_query_count)
                query->startup_sent++;
 
-       RCU_INIT_POINTER(querier->port, NULL);
+       querier->port_ifidx = 0;
        br_multicast_send_query(brmctx, NULL, query);
 out:
        spin_unlock(&brmctx->br->multicast_lock);
@@ -3732,12 +3734,12 @@ void br_multicast_ctx_init(struct net_bridge *br,
        brmctx->multicast_membership_interval = 260 * HZ;
 
        brmctx->ip4_other_query.delay_time = 0;
-       brmctx->ip4_querier.port = NULL;
+       brmctx->ip4_querier.port_ifidx = 0;
        brmctx->multicast_igmp_version = 2;
 #if IS_ENABLED(CONFIG_IPV6)
        brmctx->multicast_mld_version = 1;
        brmctx->ip6_other_query.delay_time = 0;
-       brmctx->ip6_querier.port = NULL;
+       brmctx->ip6_querier.port_ifidx = 0;
 #endif
 
        timer_setup(&brmctx->ip4_mc_router_timer,
@@ -4479,6 +4481,7 @@ bool br_multicast_has_querier_adjacent(struct net_device *dev, int proto)
        struct net_bridge *br;
        struct net_bridge_port *port;
        bool ret = false;
+       int port_ifidx;
 
        rcu_read_lock();
        if (!netif_is_bridge_port(dev))
@@ -4493,14 +4496,16 @@ bool br_multicast_has_querier_adjacent(struct net_device *dev, int proto)
 
        switch (proto) {
        case ETH_P_IP:
+               port_ifidx = brmctx->ip4_querier.port_ifidx;
                if (!timer_pending(&brmctx->ip4_other_query.timer) ||
-                   rcu_dereference(brmctx->ip4_querier.port) == port)
+                   port_ifidx == port->dev->ifindex)
                        goto unlock;
                break;
 #if IS_ENABLED(CONFIG_IPV6)
        case ETH_P_IPV6:
+               port_ifidx = brmctx->ip6_querier.port_ifidx;
                if (!timer_pending(&brmctx->ip6_other_query.timer) ||
-                   rcu_dereference(brmctx->ip6_querier.port) == port)
+                   port_ifidx == port->dev->ifindex)
                        goto unlock;
                break;
 #endif
index c4a8fee990c914628f6468beae9832b65702e54d..30ca978676f3faaa10886d97dda06935bcd74621 100644 (file)
@@ -81,7 +81,7 @@ struct bridge_mcast_other_query {
 /* selected querier */
 struct bridge_mcast_querier {
        struct br_ip addr;
-       struct net_bridge_port __rcu    *port;
+       int port_ifidx;
 };
 
 /* IGMP/MLD statistics */