aboutsummaryrefslogtreecommitdiffstats
path: root/net/bridge
diff options
context:
space:
mode:
authorEric Dumazet <eric.dumazet@gmail.com>2010-11-15 01:38:10 -0500
committerDavid S. Miller <davem@davemloft.net>2010-11-15 14:13:16 -0500
commite80516880019aa1f7c5c410276edfea9575ec89f (patch)
treeb17f51f56ef97e5a366f2f5bc3020935d8eb5def /net/bridge
parent8a22c99a80b0926585cfcbcc423ee2c49c1fd820 (diff)
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 <eric.dumazet@gmail.com> Signed-off-by: Stephen Hemminger <shemminger@vyatta.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/bridge')
-rw-r--r--net/bridge/br_forward.c4
-rw-r--r--net/bridge/br_multicast.c78
-rw-r--r--net/bridge/br_private.h6
3 files changed, 56 insertions, 32 deletions
diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c
index cbfe87f0f34a..2bd11ec6d166 100644
--- a/net/bridge/br_forward.c
+++ b/net/bridge/br_forward.c
@@ -223,7 +223,7 @@ static void br_multicast_flood(struct net_bridge_mdb_entry *mdst,
223 struct net_bridge_port_group *p; 223 struct net_bridge_port_group *p;
224 struct hlist_node *rp; 224 struct hlist_node *rp;
225 225
226 rp = rcu_dereference(br->router_list.first); 226 rp = rcu_dereference(hlist_first_rcu(&br->router_list));
227 p = mdst ? rcu_dereference(mdst->ports) : NULL; 227 p = mdst ? rcu_dereference(mdst->ports) : NULL;
228 while (p || rp) { 228 while (p || rp) {
229 struct net_bridge_port *port, *lport, *rport; 229 struct net_bridge_port *port, *lport, *rport;
@@ -242,7 +242,7 @@ static void br_multicast_flood(struct net_bridge_mdb_entry *mdst,
242 if ((unsigned long)lport >= (unsigned long)port) 242 if ((unsigned long)lport >= (unsigned long)port)
243 p = rcu_dereference(p->next); 243 p = rcu_dereference(p->next);
244 if ((unsigned long)rport >= (unsigned long)port) 244 if ((unsigned long)rport >= (unsigned long)port)
245 rp = rcu_dereference(rp->next); 245 rp = rcu_dereference(hlist_next_rcu(rp));
246 } 246 }
247 247
248 if (!prev) 248 if (!prev)
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index eb5b256ffc88..326e599f83fb 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -33,6 +33,9 @@
33 33
34#include "br_private.h" 34#include "br_private.h"
35 35
36#define mlock_dereference(X, br) \
37 rcu_dereference_protected(X, lockdep_is_held(&br->multicast_lock))
38
36#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 39#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
37static inline int ipv6_is_local_multicast(const struct in6_addr *addr) 40static inline int ipv6_is_local_multicast(const struct in6_addr *addr)
38{ 41{
@@ -135,7 +138,7 @@ static struct net_bridge_mdb_entry *br_mdb_ip6_get(
135struct net_bridge_mdb_entry *br_mdb_get(struct net_bridge *br, 138struct net_bridge_mdb_entry *br_mdb_get(struct net_bridge *br,
136 struct sk_buff *skb) 139 struct sk_buff *skb)
137{ 140{
138 struct net_bridge_mdb_htable *mdb = br->mdb; 141 struct net_bridge_mdb_htable *mdb = rcu_dereference(br->mdb);
139 struct br_ip ip; 142 struct br_ip ip;
140 143
141 if (br->multicast_disabled) 144 if (br->multicast_disabled)
@@ -235,7 +238,8 @@ static void br_multicast_group_expired(unsigned long data)
235 if (mp->ports) 238 if (mp->ports)
236 goto out; 239 goto out;
237 240
238 mdb = br->mdb; 241 mdb = mlock_dereference(br->mdb, br);
242
239 hlist_del_rcu(&mp->hlist[mdb->ver]); 243 hlist_del_rcu(&mp->hlist[mdb->ver]);
240 mdb->size--; 244 mdb->size--;
241 245
@@ -249,16 +253,20 @@ out:
249static void br_multicast_del_pg(struct net_bridge *br, 253static void br_multicast_del_pg(struct net_bridge *br,
250 struct net_bridge_port_group *pg) 254 struct net_bridge_port_group *pg)
251{ 255{
252 struct net_bridge_mdb_htable *mdb = br->mdb; 256 struct net_bridge_mdb_htable *mdb;
253 struct net_bridge_mdb_entry *mp; 257 struct net_bridge_mdb_entry *mp;
254 struct net_bridge_port_group *p; 258 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);
256 262
257 mp = br_mdb_ip_get(mdb, &pg->addr); 263 mp = br_mdb_ip_get(mdb, &pg->addr);
258 if (WARN_ON(!mp)) 264 if (WARN_ON(!mp))
259 return; 265 return;
260 266
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) {
262 if (p != pg) 270 if (p != pg)
263 continue; 271 continue;
264 272
@@ -294,10 +302,10 @@ out:
294 spin_unlock(&br->multicast_lock); 302 spin_unlock(&br->multicast_lock);
295} 303}
296 304
297static int br_mdb_rehash(struct net_bridge_mdb_htable **mdbp, int max, 305static int br_mdb_rehash(struct net_bridge_mdb_htable __rcu **mdbp, int max,
298 int elasticity) 306 int elasticity)
299{ 307{
300 struct net_bridge_mdb_htable *old = *mdbp; 308 struct net_bridge_mdb_htable *old = rcu_dereference_protected(*mdbp, 1);
301 struct net_bridge_mdb_htable *mdb; 309 struct net_bridge_mdb_htable *mdb;
302 int err; 310 int err;
303 311
@@ -569,7 +577,7 @@ static struct net_bridge_mdb_entry *br_multicast_get_group(
569 struct net_bridge *br, struct net_bridge_port *port, 577 struct net_bridge *br, struct net_bridge_port *port,
570 struct br_ip *group, int hash) 578 struct br_ip *group, int hash)
571{ 579{
572 struct net_bridge_mdb_htable *mdb = br->mdb; 580 struct net_bridge_mdb_htable *mdb;
573 struct net_bridge_mdb_entry *mp; 581 struct net_bridge_mdb_entry *mp;
574 struct hlist_node *p; 582 struct hlist_node *p;
575 unsigned count = 0; 583 unsigned count = 0;
@@ -577,6 +585,7 @@ static struct net_bridge_mdb_entry *br_multicast_get_group(
577 int elasticity; 585 int elasticity;
578 int err; 586 int err;
579 587
588 mdb = rcu_dereference_protected(br->mdb, 1);
580 hlist_for_each_entry(mp, p, &mdb->mhash[hash], hlist[mdb->ver]) { 589 hlist_for_each_entry(mp, p, &mdb->mhash[hash], hlist[mdb->ver]) {
581 count++; 590 count++;
582 if (unlikely(br_ip_equal(group, &mp->addr))) 591 if (unlikely(br_ip_equal(group, &mp->addr)))
@@ -642,10 +651,11 @@ static struct net_bridge_mdb_entry *br_multicast_new_group(
642 struct net_bridge *br, struct net_bridge_port *port, 651 struct net_bridge *br, struct net_bridge_port *port,
643 struct br_ip *group) 652 struct br_ip *group)
644{ 653{
645 struct net_bridge_mdb_htable *mdb = br->mdb; 654 struct net_bridge_mdb_htable *mdb;
646 struct net_bridge_mdb_entry *mp; 655 struct net_bridge_mdb_entry *mp;
647 int hash; 656 int hash;
648 657
658 mdb = rcu_dereference_protected(br->mdb, 1);
649 if (!mdb) { 659 if (!mdb) {
650 if (br_mdb_rehash(&br->mdb, BR_HASH_SIZE, 0)) 660 if (br_mdb_rehash(&br->mdb, BR_HASH_SIZE, 0))
651 return NULL; 661 return NULL;
@@ -660,7 +670,7 @@ static struct net_bridge_mdb_entry *br_multicast_new_group(
660 670
661 case -EAGAIN: 671 case -EAGAIN:
662rehash: 672rehash:
663 mdb = br->mdb; 673 mdb = rcu_dereference_protected(br->mdb, 1);
664 hash = br_ip_hash(mdb, group); 674 hash = br_ip_hash(mdb, group);
665 break; 675 break;
666 676
@@ -692,7 +702,7 @@ static int br_multicast_add_group(struct net_bridge *br,
692{ 702{
693 struct net_bridge_mdb_entry *mp; 703 struct net_bridge_mdb_entry *mp;
694 struct net_bridge_port_group *p; 704 struct net_bridge_port_group *p;
695 struct net_bridge_port_group **pp; 705 struct net_bridge_port_group __rcu **pp;
696 unsigned long now = jiffies; 706 unsigned long now = jiffies;
697 int err; 707 int err;
698 708
@@ -712,7 +722,9 @@ static int br_multicast_add_group(struct net_bridge *br,
712 goto out; 722 goto out;
713 } 723 }
714 724
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) {
716 if (p->port == port) 728 if (p->port == port)
717 goto found; 729 goto found;
718 if ((unsigned long)p->port < (unsigned long)port) 730 if ((unsigned long)p->port < (unsigned long)port)
@@ -1106,7 +1118,7 @@ static int br_ip4_multicast_query(struct net_bridge *br,
1106 struct net_bridge_mdb_entry *mp; 1118 struct net_bridge_mdb_entry *mp;
1107 struct igmpv3_query *ih3; 1119 struct igmpv3_query *ih3;
1108 struct net_bridge_port_group *p; 1120 struct net_bridge_port_group *p;
1109 struct net_bridge_port_group **pp; 1121 struct net_bridge_port_group __rcu **pp;
1110 unsigned long max_delay; 1122 unsigned long max_delay;
1111 unsigned long now = jiffies; 1123 unsigned long now = jiffies;
1112 __be32 group; 1124 __be32 group;
@@ -1145,7 +1157,7 @@ static int br_ip4_multicast_query(struct net_bridge *br,
1145 if (!group) 1157 if (!group)
1146 goto out; 1158 goto out;
1147 1159
1148 mp = br_mdb_ip4_get(br->mdb, group); 1160 mp = br_mdb_ip4_get(mlock_dereference(br->mdb, br), group);
1149 if (!mp) 1161 if (!mp)
1150 goto out; 1162 goto out;
1151 1163
@@ -1157,7 +1169,9 @@ static int br_ip4_multicast_query(struct net_bridge *br,
1157 try_to_del_timer_sync(&mp->timer) >= 0)) 1169 try_to_del_timer_sync(&mp->timer) >= 0))
1158 mod_timer(&mp->timer, now + max_delay); 1170 mod_timer(&mp->timer, now + max_delay);
1159 1171
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) {
1161 if (timer_pending(&p->timer) ? 1175 if (timer_pending(&p->timer) ?
1162 time_after(p->timer.expires, now + max_delay) : 1176 time_after(p->timer.expires, now + max_delay) :
1163 try_to_del_timer_sync(&p->timer) >= 0) 1177 try_to_del_timer_sync(&p->timer) >= 0)
@@ -1178,7 +1192,8 @@ static int br_ip6_multicast_query(struct net_bridge *br,
1178 struct mld_msg *mld = (struct mld_msg *) icmp6_hdr(skb); 1192 struct mld_msg *mld = (struct mld_msg *) icmp6_hdr(skb);
1179 struct net_bridge_mdb_entry *mp; 1193 struct net_bridge_mdb_entry *mp;
1180 struct mld2_query *mld2q; 1194 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;
1182 unsigned long max_delay; 1197 unsigned long max_delay;
1183 unsigned long now = jiffies; 1198 unsigned long now = jiffies;
1184 struct in6_addr *group = NULL; 1199 struct in6_addr *group = NULL;
@@ -1214,7 +1229,7 @@ static int br_ip6_multicast_query(struct net_bridge *br,
1214 if (!group) 1229 if (!group)
1215 goto out; 1230 goto out;
1216 1231
1217 mp = br_mdb_ip6_get(br->mdb, group); 1232 mp = br_mdb_ip6_get(mlock_dereference(br->mdb, br), group);
1218 if (!mp) 1233 if (!mp)
1219 goto out; 1234 goto out;
1220 1235
@@ -1225,7 +1240,9 @@ static int br_ip6_multicast_query(struct net_bridge *br,
1225 try_to_del_timer_sync(&mp->timer) >= 0)) 1240 try_to_del_timer_sync(&mp->timer) >= 0))
1226 mod_timer(&mp->timer, now + max_delay); 1241 mod_timer(&mp->timer, now + max_delay);
1227 1242
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) {
1229 if (timer_pending(&p->timer) ? 1246 if (timer_pending(&p->timer) ?
1230 time_after(p->timer.expires, now + max_delay) : 1247 time_after(p->timer.expires, now + max_delay) :
1231 try_to_del_timer_sync(&p->timer) >= 0) 1248 try_to_del_timer_sync(&p->timer) >= 0)
@@ -1254,7 +1271,7 @@ static void br_multicast_leave_group(struct net_bridge *br,
1254 timer_pending(&br->multicast_querier_timer)) 1271 timer_pending(&br->multicast_querier_timer))
1255 goto out; 1272 goto out;
1256 1273
1257 mdb = br->mdb; 1274 mdb = mlock_dereference(br->mdb, br);
1258 mp = br_mdb_ip_get(mdb, group); 1275 mp = br_mdb_ip_get(mdb, group);
1259 if (!mp) 1276 if (!mp)
1260 goto out; 1277 goto out;
@@ -1277,7 +1294,9 @@ static void br_multicast_leave_group(struct net_bridge *br,
1277 goto out; 1294 goto out;
1278 } 1295 }
1279 1296
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)) {
1281 if (p->port != port) 1300 if (p->port != port)
1282 continue; 1301 continue;
1283 1302
@@ -1625,7 +1644,7 @@ void br_multicast_stop(struct net_bridge *br)
1625 del_timer_sync(&br->multicast_query_timer); 1644 del_timer_sync(&br->multicast_query_timer);
1626 1645
1627 spin_lock_bh(&br->multicast_lock); 1646 spin_lock_bh(&br->multicast_lock);
1628 mdb = br->mdb; 1647 mdb = mlock_dereference(br->mdb, br);
1629 if (!mdb) 1648 if (!mdb)
1630 goto out; 1649 goto out;
1631 1650
@@ -1729,6 +1748,7 @@ int br_multicast_toggle(struct net_bridge *br, unsigned long val)
1729{ 1748{
1730 struct net_bridge_port *port; 1749 struct net_bridge_port *port;
1731 int err = 0; 1750 int err = 0;
1751 struct net_bridge_mdb_htable *mdb;
1732 1752
1733 spin_lock(&br->multicast_lock); 1753 spin_lock(&br->multicast_lock);
1734 if (br->multicast_disabled == !val) 1754 if (br->multicast_disabled == !val)
@@ -1741,15 +1761,16 @@ int br_multicast_toggle(struct net_bridge *br, unsigned long val)
1741 if (!netif_running(br->dev)) 1761 if (!netif_running(br->dev))
1742 goto unlock; 1762 goto unlock;
1743 1763
1744 if (br->mdb) { 1764 mdb = mlock_dereference(br->mdb, br);
1745 if (br->mdb->old) { 1765 if (mdb) {
1766 if (mdb->old) {
1746 err = -EEXIST; 1767 err = -EEXIST;
1747rollback: 1768rollback:
1748 br->multicast_disabled = !!val; 1769 br->multicast_disabled = !!val;
1749 goto unlock; 1770 goto unlock;
1750 } 1771 }
1751 1772
1752 err = br_mdb_rehash(&br->mdb, br->mdb->max, 1773 err = br_mdb_rehash(&br->mdb, mdb->max,
1753 br->hash_elasticity); 1774 br->hash_elasticity);
1754 if (err) 1775 if (err)
1755 goto rollback; 1776 goto rollback;
@@ -1774,6 +1795,7 @@ int br_multicast_set_hash_max(struct net_bridge *br, unsigned long val)
1774{ 1795{
1775 int err = -ENOENT; 1796 int err = -ENOENT;
1776 u32 old; 1797 u32 old;
1798 struct net_bridge_mdb_htable *mdb;
1777 1799
1778 spin_lock(&br->multicast_lock); 1800 spin_lock(&br->multicast_lock);
1779 if (!netif_running(br->dev)) 1801 if (!netif_running(br->dev))
@@ -1782,7 +1804,9 @@ int br_multicast_set_hash_max(struct net_bridge *br, unsigned long val)
1782 err = -EINVAL; 1804 err = -EINVAL;
1783 if (!is_power_of_2(val)) 1805 if (!is_power_of_2(val))
1784 goto unlock; 1806 goto unlock;
1785 if (br->mdb && val < br->mdb->size) 1807
1808 mdb = mlock_dereference(br->mdb, br);
1809 if (mdb && val < mdb->size)
1786 goto unlock; 1810 goto unlock;
1787 1811
1788 err = 0; 1812 err = 0;
@@ -1790,8 +1814,8 @@ int br_multicast_set_hash_max(struct net_bridge *br, unsigned long val)
1790 old = br->hash_max; 1814 old = br->hash_max;
1791 br->hash_max = val; 1815 br->hash_max = val;
1792 1816
1793 if (br->mdb) { 1817 if (mdb) {
1794 if (br->mdb->old) { 1818 if (mdb->old) {
1795 err = -EEXIST; 1819 err = -EEXIST;
1796rollback: 1820rollback:
1797 br->hash_max = old; 1821 br->hash_max = old;
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 75c90edaf7db..b862071bf601 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -72,7 +72,7 @@ struct net_bridge_fdb_entry
72 72
73struct net_bridge_port_group { 73struct net_bridge_port_group {
74 struct net_bridge_port *port; 74 struct net_bridge_port *port;
75 struct net_bridge_port_group *next; 75 struct net_bridge_port_group __rcu *next;
76 struct hlist_node mglist; 76 struct hlist_node mglist;
77 struct rcu_head rcu; 77 struct rcu_head rcu;
78 struct timer_list timer; 78 struct timer_list timer;
@@ -86,7 +86,7 @@ struct net_bridge_mdb_entry
86 struct hlist_node hlist[2]; 86 struct hlist_node hlist[2];
87 struct hlist_node mglist; 87 struct hlist_node mglist;
88 struct net_bridge *br; 88 struct net_bridge *br;
89 struct net_bridge_port_group *ports; 89 struct net_bridge_port_group __rcu *ports;
90 struct rcu_head rcu; 90 struct rcu_head rcu;
91 struct timer_list timer; 91 struct timer_list timer;
92 struct timer_list query_timer; 92 struct timer_list query_timer;
@@ -227,7 +227,7 @@ struct net_bridge
227 unsigned long multicast_startup_query_interval; 227 unsigned long multicast_startup_query_interval;
228 228
229 spinlock_t multicast_lock; 229 spinlock_t multicast_lock;
230 struct net_bridge_mdb_htable *mdb; 230 struct net_bridge_mdb_htable __rcu *mdb;
231 struct hlist_head router_list; 231 struct hlist_head router_list;
232 struct hlist_head mglist; 232 struct hlist_head mglist;
233 233