Skip to content

Commit 74edfd4

Browse files
Nikolay Aleksandrovdavem330
authored andcommitted
net: bridge: multicast: add helper to get port mcast context from port group
Add br_multicast_pg_to_port_ctx() which returns the proper port multicast context from either port or vlan based on bridge option and vlan flags. As the comment inside explains the locking is a bit tricky, we rely on the fact that BR_VLFLAG_MCAST_ENABLED requires multicast_lock to change and we also require it to be held to call that helper. If we find the vlan under rcu and it still has the flag then we can be sure it will be alive until we unlock multicast_lock which should be enough. Note that the context might change from vlan to bridge between different calls to this helper as the mcast vlan knob requires only rtnl so it should be used carefully and for read-only/check purposes. Signed-off-by: Nikolay Aleksandrov <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent f4b7002 commit 74edfd4

File tree

1 file changed

+38
-0
lines changed

1 file changed

+38
-0
lines changed

net/bridge/br_multicast.c

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,44 @@ struct net_bridge_mdb_entry *br_mdb_get(struct net_bridge_mcast *brmctx,
192192
return br_mdb_ip_get_rcu(br, &ip);
193193
}
194194

195+
/* IMPORTANT: this function must be used only when the contexts cannot be
196+
* passed down (e.g. timer) and must be used for read-only purposes because
197+
* the vlan snooping option can change, so it can return any context
198+
* (non-vlan or vlan). Its initial intended purpose is to read timer values
199+
* from the *current* context based on the option. At worst that could lead
200+
* to inconsistent timers when the contexts are changed, i.e. src timer
201+
* which needs to re-arm with a specific delay taken from the old context
202+
*/
203+
static struct net_bridge_mcast_port *
204+
br_multicast_pg_to_port_ctx(const struct net_bridge_port_group *pg)
205+
{
206+
struct net_bridge_mcast_port *pmctx = &pg->key.port->multicast_ctx;
207+
struct net_bridge_vlan *vlan;
208+
209+
lockdep_assert_held_once(&pg->key.port->br->multicast_lock);
210+
211+
/* if vlan snooping is disabled use the port's multicast context */
212+
if (!pg->key.addr.vid ||
213+
!br_opt_get(pg->key.port->br, BROPT_MCAST_VLAN_SNOOPING_ENABLED))
214+
goto out;
215+
216+
/* locking is tricky here, due to different rules for multicast and
217+
* vlans we need to take rcu to find the vlan and make sure it has
218+
* the BR_VLFLAG_MCAST_ENABLED flag set, it can only change under
219+
* multicast_lock which must be already held here, so the vlan's pmctx
220+
* can safely be used on return
221+
*/
222+
rcu_read_lock();
223+
vlan = br_vlan_find(nbp_vlan_group(pg->key.port), pg->key.addr.vid);
224+
if (vlan && !br_multicast_port_ctx_vlan_disabled(&vlan->port_mcast_ctx))
225+
pmctx = &vlan->port_mcast_ctx;
226+
else
227+
pmctx = NULL;
228+
rcu_read_unlock();
229+
out:
230+
return pmctx;
231+
}
232+
195233
static bool br_port_group_equal(struct net_bridge_port_group *p,
196234
struct net_bridge_port *port,
197235
const unsigned char *src)

0 commit comments

Comments
 (0)