aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCong Wang <amwang@redhat.com>2013-05-21 17:52:55 -0400
committerDavid S. Miller <davem@davemloft.net>2013-05-22 17:54:37 -0400
commit9f00b2e7cf241fa389733d41b615efdaa2cb0f5b (patch)
tree3426d01fdec8b2419cdb72f597f1f9e5336a7643
parent1c8ad5bfa2be5025b0c81e3c2decd0574d453ab1 (diff)
bridge: only expire the mdb entry when query is received
Currently we arm the expire timer when the mdb entry is added, however, this causes problem when there is no querier sent out after that. So we should only arm the timer when a corresponding query is received, as suggested by Herbert. And he also mentioned "if there is no querier then group subscriptions shouldn't expire. There has to be at least one querier in the network for this thing to work. Otherwise it just degenerates into a non-snooping switch, which is OK." Cc: Herbert Xu <herbert@gondor.apana.org.au> Cc: Stephen Hemminger <stephen@networkplumber.org> Cc: "David S. Miller" <davem@davemloft.net> Cc: Adam Baker <linux@baker-net.org.uk> Signed-off-by: Cong Wang <amwang@redhat.com> Acked-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/bridge/br_multicast.c39
-rw-r--r--net/bridge/br_private.h1
2 files changed, 13 insertions, 27 deletions
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 247514793101..40bda804fbd9 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -617,8 +617,6 @@ rehash:
617 617
618 mp->br = br; 618 mp->br = br;
619 mp->addr = *group; 619 mp->addr = *group;
620 setup_timer(&mp->timer, br_multicast_group_expired,
621 (unsigned long)mp);
622 620
623 hlist_add_head_rcu(&mp->hlist[mdb->ver], &mdb->mhash[hash]); 621 hlist_add_head_rcu(&mp->hlist[mdb->ver], &mdb->mhash[hash]);
624 mdb->size++; 622 mdb->size++;
@@ -656,7 +654,6 @@ static int br_multicast_add_group(struct net_bridge *br,
656 struct net_bridge_mdb_entry *mp; 654 struct net_bridge_mdb_entry *mp;
657 struct net_bridge_port_group *p; 655 struct net_bridge_port_group *p;
658 struct net_bridge_port_group __rcu **pp; 656 struct net_bridge_port_group __rcu **pp;
659 unsigned long now = jiffies;
660 int err; 657 int err;
661 658
662 spin_lock(&br->multicast_lock); 659 spin_lock(&br->multicast_lock);
@@ -671,7 +668,6 @@ static int br_multicast_add_group(struct net_bridge *br,
671 668
672 if (!port) { 669 if (!port) {
673 mp->mglist = true; 670 mp->mglist = true;
674 mod_timer(&mp->timer, now + br->multicast_membership_interval);
675 goto out; 671 goto out;
676 } 672 }
677 673
@@ -679,7 +675,7 @@ static int br_multicast_add_group(struct net_bridge *br,
679 (p = mlock_dereference(*pp, br)) != NULL; 675 (p = mlock_dereference(*pp, br)) != NULL;
680 pp = &p->next) { 676 pp = &p->next) {
681 if (p->port == port) 677 if (p->port == port)
682 goto found; 678 goto out;
683 if ((unsigned long)p->port < (unsigned long)port) 679 if ((unsigned long)p->port < (unsigned long)port)
684 break; 680 break;
685 } 681 }
@@ -690,8 +686,6 @@ static int br_multicast_add_group(struct net_bridge *br,
690 rcu_assign_pointer(*pp, p); 686 rcu_assign_pointer(*pp, p);
691 br_mdb_notify(br->dev, port, group, RTM_NEWMDB); 687 br_mdb_notify(br->dev, port, group, RTM_NEWMDB);
692 688
693found:
694 mod_timer(&p->timer, now + br->multicast_membership_interval);
695out: 689out:
696 err = 0; 690 err = 0;
697 691
@@ -1131,6 +1125,10 @@ static int br_ip4_multicast_query(struct net_bridge *br,
1131 if (!mp) 1125 if (!mp)
1132 goto out; 1126 goto out;
1133 1127
1128 setup_timer(&mp->timer, br_multicast_group_expired, (unsigned long)mp);
1129 mod_timer(&mp->timer, now + br->multicast_membership_interval);
1130 mp->timer_armed = true;
1131
1134 max_delay *= br->multicast_last_member_count; 1132 max_delay *= br->multicast_last_member_count;
1135 1133
1136 if (mp->mglist && 1134 if (mp->mglist &&
@@ -1205,6 +1203,10 @@ static int br_ip6_multicast_query(struct net_bridge *br,
1205 if (!mp) 1203 if (!mp)
1206 goto out; 1204 goto out;
1207 1205
1206 setup_timer(&mp->timer, br_multicast_group_expired, (unsigned long)mp);
1207 mod_timer(&mp->timer, now + br->multicast_membership_interval);
1208 mp->timer_armed = true;
1209
1208 max_delay *= br->multicast_last_member_count; 1210 max_delay *= br->multicast_last_member_count;
1209 if (mp->mglist && 1211 if (mp->mglist &&
1210 (timer_pending(&mp->timer) ? 1212 (timer_pending(&mp->timer) ?
@@ -1263,7 +1265,7 @@ static void br_multicast_leave_group(struct net_bridge *br,
1263 call_rcu_bh(&p->rcu, br_multicast_free_pg); 1265 call_rcu_bh(&p->rcu, br_multicast_free_pg);
1264 br_mdb_notify(br->dev, port, group, RTM_DELMDB); 1266 br_mdb_notify(br->dev, port, group, RTM_DELMDB);
1265 1267
1266 if (!mp->ports && !mp->mglist && 1268 if (!mp->ports && !mp->mglist && mp->timer_armed &&
1267 netif_running(br->dev)) 1269 netif_running(br->dev))
1268 mod_timer(&mp->timer, jiffies); 1270 mod_timer(&mp->timer, jiffies);
1269 } 1271 }
@@ -1275,30 +1277,12 @@ static void br_multicast_leave_group(struct net_bridge *br,
1275 br->multicast_last_member_interval; 1277 br->multicast_last_member_interval;
1276 1278
1277 if (!port) { 1279 if (!port) {
1278 if (mp->mglist && 1280 if (mp->mglist && mp->timer_armed &&
1279 (timer_pending(&mp->timer) ? 1281 (timer_pending(&mp->timer) ?
1280 time_after(mp->timer.expires, time) : 1282 time_after(mp->timer.expires, time) :
1281 try_to_del_timer_sync(&mp->timer) >= 0)) { 1283 try_to_del_timer_sync(&mp->timer) >= 0)) {
1282 mod_timer(&mp->timer, time); 1284 mod_timer(&mp->timer, time);
1283 } 1285 }
1284
1285 goto out;
1286 }
1287
1288 for (p = mlock_dereference(mp->ports, br);
1289 p != NULL;
1290 p = mlock_dereference(p->next, br)) {
1291 if (p->port != port)
1292 continue;
1293
1294 if (!hlist_unhashed(&p->mglist) &&
1295 (timer_pending(&p->timer) ?
1296 time_after(p->timer.expires, time) :
1297 try_to_del_timer_sync(&p->timer) >= 0)) {
1298 mod_timer(&p->timer, time);
1299 }
1300
1301 break;
1302 } 1286 }
1303 1287
1304out: 1288out:
@@ -1674,6 +1658,7 @@ void br_multicast_stop(struct net_bridge *br)
1674 hlist_for_each_entry_safe(mp, n, &mdb->mhash[i], 1658 hlist_for_each_entry_safe(mp, n, &mdb->mhash[i],
1675 hlist[ver]) { 1659 hlist[ver]) {
1676 del_timer(&mp->timer); 1660 del_timer(&mp->timer);
1661 mp->timer_armed = false;
1677 call_rcu_bh(&mp->rcu, br_multicast_free_group); 1662 call_rcu_bh(&mp->rcu, br_multicast_free_group);
1678 } 1663 }
1679 } 1664 }
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index e260710a01d4..1b0ac95a5c37 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -112,6 +112,7 @@ struct net_bridge_mdb_entry
112 struct timer_list timer; 112 struct timer_list timer;
113 struct br_ip addr; 113 struct br_ip addr;
114 bool mglist; 114 bool mglist;
115 bool timer_armed;
115}; 116};
116 117
117struct net_bridge_mdb_htable 118struct net_bridge_mdb_htable