Skip to content

Commit e805168

Browse files
Eric Dumazetdavem330
authored andcommitted
bridge: add RCU annotation to bridge multicast table
Add modern __rcu annotatations to bridge multicast table. Use newer hlist macros to avoid direct access to hlist internals. Signed-off-by: Eric Dumazet <[email protected]> Signed-off-by: Stephen Hemminger <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 8a22c99 commit e805168

File tree

3 files changed

+56
-32
lines changed

3 files changed

+56
-32
lines changed

net/bridge/br_forward.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ static void br_multicast_flood(struct net_bridge_mdb_entry *mdst,
223223
struct net_bridge_port_group *p;
224224
struct hlist_node *rp;
225225

226-
rp = rcu_dereference(br->router_list.first);
226+
rp = rcu_dereference(hlist_first_rcu(&br->router_list));
227227
p = mdst ? rcu_dereference(mdst->ports) : NULL;
228228
while (p || rp) {
229229
struct net_bridge_port *port, *lport, *rport;
@@ -242,7 +242,7 @@ static void br_multicast_flood(struct net_bridge_mdb_entry *mdst,
242242
if ((unsigned long)lport >= (unsigned long)port)
243243
p = rcu_dereference(p->next);
244244
if ((unsigned long)rport >= (unsigned long)port)
245-
rp = rcu_dereference(rp->next);
245+
rp = rcu_dereference(hlist_next_rcu(rp));
246246
}
247247

248248
if (!prev)

net/bridge/br_multicast.c

Lines changed: 51 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@
3333

3434
#include "br_private.h"
3535

36+
#define mlock_dereference(X, br) \
37+
rcu_dereference_protected(X, lockdep_is_held(&br->multicast_lock))
38+
3639
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
3740
static inline int ipv6_is_local_multicast(const struct in6_addr *addr)
3841
{
@@ -135,7 +138,7 @@ static struct net_bridge_mdb_entry *br_mdb_ip6_get(
135138
struct net_bridge_mdb_entry *br_mdb_get(struct net_bridge *br,
136139
struct sk_buff *skb)
137140
{
138-
struct net_bridge_mdb_htable *mdb = br->mdb;
141+
struct net_bridge_mdb_htable *mdb = rcu_dereference(br->mdb);
139142
struct br_ip ip;
140143

141144
if (br->multicast_disabled)
@@ -235,7 +238,8 @@ static void br_multicast_group_expired(unsigned long data)
235238
if (mp->ports)
236239
goto out;
237240

238-
mdb = br->mdb;
241+
mdb = mlock_dereference(br->mdb, br);
242+
239243
hlist_del_rcu(&mp->hlist[mdb->ver]);
240244
mdb->size--;
241245

@@ -249,16 +253,20 @@ static void br_multicast_group_expired(unsigned long data)
249253
static void br_multicast_del_pg(struct net_bridge *br,
250254
struct net_bridge_port_group *pg)
251255
{
252-
struct net_bridge_mdb_htable *mdb = br->mdb;
256+
struct net_bridge_mdb_htable *mdb;
253257
struct net_bridge_mdb_entry *mp;
254258
struct net_bridge_port_group *p;
255-
struct net_bridge_port_group **pp;
259+
struct net_bridge_port_group __rcu **pp;
260+
261+
mdb = mlock_dereference(br->mdb, br);
256262

257263
mp = br_mdb_ip_get(mdb, &pg->addr);
258264
if (WARN_ON(!mp))
259265
return;
260266

261-
for (pp = &mp->ports; (p = *pp); pp = &p->next) {
267+
for (pp = &mp->ports;
268+
(p = mlock_dereference(*pp, br)) != NULL;
269+
pp = &p->next) {
262270
if (p != pg)
263271
continue;
264272

@@ -294,10 +302,10 @@ static void br_multicast_port_group_expired(unsigned long data)
294302
spin_unlock(&br->multicast_lock);
295303
}
296304

297-
static int br_mdb_rehash(struct net_bridge_mdb_htable **mdbp, int max,
305+
static int br_mdb_rehash(struct net_bridge_mdb_htable __rcu **mdbp, int max,
298306
int elasticity)
299307
{
300-
struct net_bridge_mdb_htable *old = *mdbp;
308+
struct net_bridge_mdb_htable *old = rcu_dereference_protected(*mdbp, 1);
301309
struct net_bridge_mdb_htable *mdb;
302310
int err;
303311

@@ -569,14 +577,15 @@ static struct net_bridge_mdb_entry *br_multicast_get_group(
569577
struct net_bridge *br, struct net_bridge_port *port,
570578
struct br_ip *group, int hash)
571579
{
572-
struct net_bridge_mdb_htable *mdb = br->mdb;
580+
struct net_bridge_mdb_htable *mdb;
573581
struct net_bridge_mdb_entry *mp;
574582
struct hlist_node *p;
575583
unsigned count = 0;
576584
unsigned max;
577585
int elasticity;
578586
int err;
579587

588+
mdb = rcu_dereference_protected(br->mdb, 1);
580589
hlist_for_each_entry(mp, p, &mdb->mhash[hash], hlist[mdb->ver]) {
581590
count++;
582591
if (unlikely(br_ip_equal(group, &mp->addr)))
@@ -642,10 +651,11 @@ static struct net_bridge_mdb_entry *br_multicast_new_group(
642651
struct net_bridge *br, struct net_bridge_port *port,
643652
struct br_ip *group)
644653
{
645-
struct net_bridge_mdb_htable *mdb = br->mdb;
654+
struct net_bridge_mdb_htable *mdb;
646655
struct net_bridge_mdb_entry *mp;
647656
int hash;
648657

658+
mdb = rcu_dereference_protected(br->mdb, 1);
649659
if (!mdb) {
650660
if (br_mdb_rehash(&br->mdb, BR_HASH_SIZE, 0))
651661
return NULL;
@@ -660,7 +670,7 @@ static struct net_bridge_mdb_entry *br_multicast_new_group(
660670

661671
case -EAGAIN:
662672
rehash:
663-
mdb = br->mdb;
673+
mdb = rcu_dereference_protected(br->mdb, 1);
664674
hash = br_ip_hash(mdb, group);
665675
break;
666676

@@ -692,7 +702,7 @@ static int br_multicast_add_group(struct net_bridge *br,
692702
{
693703
struct net_bridge_mdb_entry *mp;
694704
struct net_bridge_port_group *p;
695-
struct net_bridge_port_group **pp;
705+
struct net_bridge_port_group __rcu **pp;
696706
unsigned long now = jiffies;
697707
int err;
698708

@@ -712,7 +722,9 @@ static int br_multicast_add_group(struct net_bridge *br,
712722
goto out;
713723
}
714724

715-
for (pp = &mp->ports; (p = *pp); pp = &p->next) {
725+
for (pp = &mp->ports;
726+
(p = mlock_dereference(*pp, br)) != NULL;
727+
pp = &p->next) {
716728
if (p->port == port)
717729
goto found;
718730
if ((unsigned long)p->port < (unsigned long)port)
@@ -1106,7 +1118,7 @@ static int br_ip4_multicast_query(struct net_bridge *br,
11061118
struct net_bridge_mdb_entry *mp;
11071119
struct igmpv3_query *ih3;
11081120
struct net_bridge_port_group *p;
1109-
struct net_bridge_port_group **pp;
1121+
struct net_bridge_port_group __rcu **pp;
11101122
unsigned long max_delay;
11111123
unsigned long now = jiffies;
11121124
__be32 group;
@@ -1145,7 +1157,7 @@ static int br_ip4_multicast_query(struct net_bridge *br,
11451157
if (!group)
11461158
goto out;
11471159

1148-
mp = br_mdb_ip4_get(br->mdb, group);
1160+
mp = br_mdb_ip4_get(mlock_dereference(br->mdb, br), group);
11491161
if (!mp)
11501162
goto out;
11511163

@@ -1157,7 +1169,9 @@ static int br_ip4_multicast_query(struct net_bridge *br,
11571169
try_to_del_timer_sync(&mp->timer) >= 0))
11581170
mod_timer(&mp->timer, now + max_delay);
11591171

1160-
for (pp = &mp->ports; (p = *pp); pp = &p->next) {
1172+
for (pp = &mp->ports;
1173+
(p = mlock_dereference(*pp, br)) != NULL;
1174+
pp = &p->next) {
11611175
if (timer_pending(&p->timer) ?
11621176
time_after(p->timer.expires, now + max_delay) :
11631177
try_to_del_timer_sync(&p->timer) >= 0)
@@ -1178,7 +1192,8 @@ static int br_ip6_multicast_query(struct net_bridge *br,
11781192
struct mld_msg *mld = (struct mld_msg *) icmp6_hdr(skb);
11791193
struct net_bridge_mdb_entry *mp;
11801194
struct mld2_query *mld2q;
1181-
struct net_bridge_port_group *p, **pp;
1195+
struct net_bridge_port_group *p;
1196+
struct net_bridge_port_group __rcu **pp;
11821197
unsigned long max_delay;
11831198
unsigned long now = jiffies;
11841199
struct in6_addr *group = NULL;
@@ -1214,7 +1229,7 @@ static int br_ip6_multicast_query(struct net_bridge *br,
12141229
if (!group)
12151230
goto out;
12161231

1217-
mp = br_mdb_ip6_get(br->mdb, group);
1232+
mp = br_mdb_ip6_get(mlock_dereference(br->mdb, br), group);
12181233
if (!mp)
12191234
goto out;
12201235

@@ -1225,7 +1240,9 @@ static int br_ip6_multicast_query(struct net_bridge *br,
12251240
try_to_del_timer_sync(&mp->timer) >= 0))
12261241
mod_timer(&mp->timer, now + max_delay);
12271242

1228-
for (pp = &mp->ports; (p = *pp); pp = &p->next) {
1243+
for (pp = &mp->ports;
1244+
(p = mlock_dereference(*pp, br)) != NULL;
1245+
pp = &p->next) {
12291246
if (timer_pending(&p->timer) ?
12301247
time_after(p->timer.expires, now + max_delay) :
12311248
try_to_del_timer_sync(&p->timer) >= 0)
@@ -1254,7 +1271,7 @@ static void br_multicast_leave_group(struct net_bridge *br,
12541271
timer_pending(&br->multicast_querier_timer))
12551272
goto out;
12561273

1257-
mdb = br->mdb;
1274+
mdb = mlock_dereference(br->mdb, br);
12581275
mp = br_mdb_ip_get(mdb, group);
12591276
if (!mp)
12601277
goto out;
@@ -1277,7 +1294,9 @@ static void br_multicast_leave_group(struct net_bridge *br,
12771294
goto out;
12781295
}
12791296

1280-
for (p = mp->ports; p; p = p->next) {
1297+
for (p = mlock_dereference(mp->ports, br);
1298+
p != NULL;
1299+
p = mlock_dereference(p->next, br)) {
12811300
if (p->port != port)
12821301
continue;
12831302

@@ -1625,7 +1644,7 @@ void br_multicast_stop(struct net_bridge *br)
16251644
del_timer_sync(&br->multicast_query_timer);
16261645

16271646
spin_lock_bh(&br->multicast_lock);
1628-
mdb = br->mdb;
1647+
mdb = mlock_dereference(br->mdb, br);
16291648
if (!mdb)
16301649
goto out;
16311650

@@ -1729,6 +1748,7 @@ int br_multicast_toggle(struct net_bridge *br, unsigned long val)
17291748
{
17301749
struct net_bridge_port *port;
17311750
int err = 0;
1751+
struct net_bridge_mdb_htable *mdb;
17321752

17331753
spin_lock(&br->multicast_lock);
17341754
if (br->multicast_disabled == !val)
@@ -1741,15 +1761,16 @@ int br_multicast_toggle(struct net_bridge *br, unsigned long val)
17411761
if (!netif_running(br->dev))
17421762
goto unlock;
17431763

1744-
if (br->mdb) {
1745-
if (br->mdb->old) {
1764+
mdb = mlock_dereference(br->mdb, br);
1765+
if (mdb) {
1766+
if (mdb->old) {
17461767
err = -EEXIST;
17471768
rollback:
17481769
br->multicast_disabled = !!val;
17491770
goto unlock;
17501771
}
17511772

1752-
err = br_mdb_rehash(&br->mdb, br->mdb->max,
1773+
err = br_mdb_rehash(&br->mdb, mdb->max,
17531774
br->hash_elasticity);
17541775
if (err)
17551776
goto rollback;
@@ -1774,6 +1795,7 @@ int br_multicast_set_hash_max(struct net_bridge *br, unsigned long val)
17741795
{
17751796
int err = -ENOENT;
17761797
u32 old;
1798+
struct net_bridge_mdb_htable *mdb;
17771799

17781800
spin_lock(&br->multicast_lock);
17791801
if (!netif_running(br->dev))
@@ -1782,16 +1804,18 @@ int br_multicast_set_hash_max(struct net_bridge *br, unsigned long val)
17821804
err = -EINVAL;
17831805
if (!is_power_of_2(val))
17841806
goto unlock;
1785-
if (br->mdb && val < br->mdb->size)
1807+
1808+
mdb = mlock_dereference(br->mdb, br);
1809+
if (mdb && val < mdb->size)
17861810
goto unlock;
17871811

17881812
err = 0;
17891813

17901814
old = br->hash_max;
17911815
br->hash_max = val;
17921816

1793-
if (br->mdb) {
1794-
if (br->mdb->old) {
1817+
if (mdb) {
1818+
if (mdb->old) {
17951819
err = -EEXIST;
17961820
rollback:
17971821
br->hash_max = old;

net/bridge/br_private.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ struct net_bridge_fdb_entry
7272

7373
struct net_bridge_port_group {
7474
struct net_bridge_port *port;
75-
struct net_bridge_port_group *next;
75+
struct net_bridge_port_group __rcu *next;
7676
struct hlist_node mglist;
7777
struct rcu_head rcu;
7878
struct timer_list timer;
@@ -86,7 +86,7 @@ struct net_bridge_mdb_entry
8686
struct hlist_node hlist[2];
8787
struct hlist_node mglist;
8888
struct net_bridge *br;
89-
struct net_bridge_port_group *ports;
89+
struct net_bridge_port_group __rcu *ports;
9090
struct rcu_head rcu;
9191
struct timer_list timer;
9292
struct timer_list query_timer;
@@ -227,7 +227,7 @@ struct net_bridge
227227
unsigned long multicast_startup_query_interval;
228228

229229
spinlock_t multicast_lock;
230-
struct net_bridge_mdb_htable *mdb;
230+
struct net_bridge_mdb_htable __rcu *mdb;
231231
struct hlist_head router_list;
232232
struct hlist_head mglist;
233233

0 commit comments

Comments
 (0)