Skip to content

Commit

Permalink
net: bridge: mcast: record querier port device ifindex instead of poi…
Browse files Browse the repository at this point in the history
…nter

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>
  • Loading branch information
Nikolay Aleksandrov authored and David S. Miller committed Aug 14, 2021
1 parent 2fa1678 commit bb18ef8
Show file tree
Hide file tree
Showing 2 changed files with 13 additions and 8 deletions.
19 changes: 12 additions & 7 deletions net/bridge/br_multicast.c
Original file line number Diff line number Diff line change
Expand Up @@ -2850,7 +2850,8 @@ static bool br_ip4_multicast_select_querier(struct net_bridge_mcast *brmctx,
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;
}
Expand All @@ -2875,7 +2876,8 @@ static bool br_ip6_multicast_select_querier(struct net_bridge_mcast *brmctx,
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;
}
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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))
Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion net/bridge/br_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down

0 comments on commit bb18ef8

Please sign in to comment.