aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorLinus Lüssing <linus.luessing@web.de>2013-10-19 18:58:57 -0400
committerDavid S. Miller <davem@davemloft.net>2013-10-22 14:41:02 -0400
commit454594f3b93a49ef568cd190c5af31376b105a7b (patch)
tree5a3109ffdd29aed110e7cd5e4295dfe0246595fd /net
parent02cf4ebd82ff0ac7254b88e466820a290ed8289a (diff)
Revert "bridge: only expire the mdb entry when query is received"
While this commit was a good attempt to fix issues occuring when no multicast querier is present, this commit still has two more issues: 1) There are cases where mdb entries do not expire even if there is a querier present. The bridge will unnecessarily continue flooding multicast packets on the according ports. 2) Never removing an mdb entry could be exploited for a Denial of Service by an attacker on the local link, slowly, but steadily eating up all memory. Actually, this commit became obsolete with "bridge: disable snooping if there is no querier" (b00589af3b) which included fixes for a few more cases. Therefore reverting the following commits (the commit stated in the commit message plus three of its follow up fixes): ==================== Revert "bridge: update mdb expiration timer upon reports." This reverts commit f144febd93d5ee534fdf23505ab091b2b9088edc. Revert "bridge: do not call setup_timer() multiple times" This reverts commit 1faabf2aab1fdaa1ace4e8c829d1b9cf7bfec2f1. Revert "bridge: fix some kernel warning in multicast timer" This reverts commit c7e8e8a8f7a70b343ca1e0f90a31e35ab2d16de1. Revert "bridge: only expire the mdb entry when query is received" This reverts commit 9f00b2e7cf241fa389733d41b615efdaa2cb0f5b. ==================== CC: Cong Wang <amwang@redhat.com> Signed-off-by: Linus Lüssing <linus.luessing@web.de> Reviewed-by: Vlad Yasevich <vyasevich@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/bridge/br_mdb.c2
-rw-r--r--net/bridge/br_multicast.c47
-rw-r--r--net/bridge/br_private.h1
3 files changed, 28 insertions, 22 deletions
diff --git a/net/bridge/br_mdb.c b/net/bridge/br_mdb.c
index 85a09bb5ca51..b7b1914dfa25 100644
--- a/net/bridge/br_mdb.c
+++ b/net/bridge/br_mdb.c
@@ -453,7 +453,7 @@ static int __br_mdb_del(struct net_bridge *br, struct br_mdb_entry *entry)
453 call_rcu_bh(&p->rcu, br_multicast_free_pg); 453 call_rcu_bh(&p->rcu, br_multicast_free_pg);
454 err = 0; 454 err = 0;
455 455
456 if (!mp->ports && !mp->mglist && mp->timer_armed && 456 if (!mp->ports && !mp->mglist &&
457 netif_running(br->dev)) 457 netif_running(br->dev))
458 mod_timer(&mp->timer, jiffies); 458 mod_timer(&mp->timer, jiffies);
459 break; 459 break;
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 1085f2180f3a..8b0b610ca2c9 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -272,7 +272,7 @@ static void br_multicast_del_pg(struct net_bridge *br,
272 del_timer(&p->timer); 272 del_timer(&p->timer);
273 call_rcu_bh(&p->rcu, br_multicast_free_pg); 273 call_rcu_bh(&p->rcu, br_multicast_free_pg);
274 274
275 if (!mp->ports && !mp->mglist && mp->timer_armed && 275 if (!mp->ports && !mp->mglist &&
276 netif_running(br->dev)) 276 netif_running(br->dev))
277 mod_timer(&mp->timer, jiffies); 277 mod_timer(&mp->timer, jiffies);
278 278
@@ -611,9 +611,6 @@ rehash:
611 break; 611 break;
612 612
613 default: 613 default:
614 /* If we have an existing entry, update it's expire timer */
615 mod_timer(&mp->timer,
616 jiffies + br->multicast_membership_interval);
617 goto out; 614 goto out;
618 } 615 }
619 616
@@ -623,7 +620,6 @@ rehash:
623 620
624 mp->br = br; 621 mp->br = br;
625 mp->addr = *group; 622 mp->addr = *group;
626
627 setup_timer(&mp->timer, br_multicast_group_expired, 623 setup_timer(&mp->timer, br_multicast_group_expired,
628 (unsigned long)mp); 624 (unsigned long)mp);
629 625
@@ -663,6 +659,7 @@ static int br_multicast_add_group(struct net_bridge *br,
663 struct net_bridge_mdb_entry *mp; 659 struct net_bridge_mdb_entry *mp;
664 struct net_bridge_port_group *p; 660 struct net_bridge_port_group *p;
665 struct net_bridge_port_group __rcu **pp; 661 struct net_bridge_port_group __rcu **pp;
662 unsigned long now = jiffies;
666 int err; 663 int err;
667 664
668 spin_lock(&br->multicast_lock); 665 spin_lock(&br->multicast_lock);
@@ -677,18 +674,15 @@ static int br_multicast_add_group(struct net_bridge *br,
677 674
678 if (!port) { 675 if (!port) {
679 mp->mglist = true; 676 mp->mglist = true;
677 mod_timer(&mp->timer, now + br->multicast_membership_interval);
680 goto out; 678 goto out;
681 } 679 }
682 680
683 for (pp = &mp->ports; 681 for (pp = &mp->ports;
684 (p = mlock_dereference(*pp, br)) != NULL; 682 (p = mlock_dereference(*pp, br)) != NULL;
685 pp = &p->next) { 683 pp = &p->next) {
686 if (p->port == port) { 684 if (p->port == port)
687 /* We already have a portgroup, update the timer. */ 685 goto found;
688 mod_timer(&p->timer,
689 jiffies + br->multicast_membership_interval);
690 goto out;
691 }
692 if ((unsigned long)p->port < (unsigned long)port) 686 if ((unsigned long)p->port < (unsigned long)port)
693 break; 687 break;
694 } 688 }
@@ -699,6 +693,8 @@ static int br_multicast_add_group(struct net_bridge *br,
699 rcu_assign_pointer(*pp, p); 693 rcu_assign_pointer(*pp, p);
700 br_mdb_notify(br->dev, port, group, RTM_NEWMDB); 694 br_mdb_notify(br->dev, port, group, RTM_NEWMDB);
701 695
696found:
697 mod_timer(&p->timer, now + br->multicast_membership_interval);
702out: 698out:
703 err = 0; 699 err = 0;
704 700
@@ -1198,9 +1194,6 @@ static int br_ip4_multicast_query(struct net_bridge *br,
1198 if (!mp) 1194 if (!mp)
1199 goto out; 1195 goto out;
1200 1196
1201 mod_timer(&mp->timer, now + br->multicast_membership_interval);
1202 mp->timer_armed = true;
1203
1204 max_delay *= br->multicast_last_member_count; 1197 max_delay *= br->multicast_last_member_count;
1205 1198
1206 if (mp->mglist && 1199 if (mp->mglist &&
@@ -1277,9 +1270,6 @@ static int br_ip6_multicast_query(struct net_bridge *br,
1277 if (!mp) 1270 if (!mp)
1278 goto out; 1271 goto out;
1279 1272
1280 mod_timer(&mp->timer, now + br->multicast_membership_interval);
1281 mp->timer_armed = true;
1282
1283 max_delay *= br->multicast_last_member_count; 1273 max_delay *= br->multicast_last_member_count;
1284 if (mp->mglist && 1274 if (mp->mglist &&
1285 (timer_pending(&mp->timer) ? 1275 (timer_pending(&mp->timer) ?
@@ -1365,7 +1355,7 @@ static void br_multicast_leave_group(struct net_bridge *br,
1365 call_rcu_bh(&p->rcu, br_multicast_free_pg); 1355 call_rcu_bh(&p->rcu, br_multicast_free_pg);
1366 br_mdb_notify(br->dev, port, group, RTM_DELMDB); 1356 br_mdb_notify(br->dev, port, group, RTM_DELMDB);
1367 1357
1368 if (!mp->ports && !mp->mglist && mp->timer_armed && 1358 if (!mp->ports && !mp->mglist &&
1369 netif_running(br->dev)) 1359 netif_running(br->dev))
1370 mod_timer(&mp->timer, jiffies); 1360 mod_timer(&mp->timer, jiffies);
1371 } 1361 }
@@ -1377,12 +1367,30 @@ static void br_multicast_leave_group(struct net_bridge *br,
1377 br->multicast_last_member_interval; 1367 br->multicast_last_member_interval;
1378 1368
1379 if (!port) { 1369 if (!port) {
1380 if (mp->mglist && mp->timer_armed && 1370 if (mp->mglist &&
1381 (timer_pending(&mp->timer) ? 1371 (timer_pending(&mp->timer) ?
1382 time_after(mp->timer.expires, time) : 1372 time_after(mp->timer.expires, time) :
1383 try_to_del_timer_sync(&mp->timer) >= 0)) { 1373 try_to_del_timer_sync(&mp->timer) >= 0)) {
1384 mod_timer(&mp->timer, time); 1374 mod_timer(&mp->timer, time);
1385 } 1375 }
1376
1377 goto out;
1378 }
1379
1380 for (p = mlock_dereference(mp->ports, br);
1381 p != NULL;
1382 p = mlock_dereference(p->next, br)) {
1383 if (p->port != port)
1384 continue;
1385
1386 if (!hlist_unhashed(&p->mglist) &&
1387 (timer_pending(&p->timer) ?
1388 time_after(p->timer.expires, time) :
1389 try_to_del_timer_sync(&p->timer) >= 0)) {
1390 mod_timer(&p->timer, time);
1391 }
1392
1393 break;
1386 } 1394 }
1387out: 1395out:
1388 spin_unlock(&br->multicast_lock); 1396 spin_unlock(&br->multicast_lock);
@@ -1805,7 +1813,6 @@ void br_multicast_stop(struct net_bridge *br)
1805 hlist_for_each_entry_safe(mp, n, &mdb->mhash[i], 1813 hlist_for_each_entry_safe(mp, n, &mdb->mhash[i],
1806 hlist[ver]) { 1814 hlist[ver]) {
1807 del_timer(&mp->timer); 1815 del_timer(&mp->timer);
1808 mp->timer_armed = false;
1809 call_rcu_bh(&mp->rcu, br_multicast_free_group); 1816 call_rcu_bh(&mp->rcu, br_multicast_free_group);
1810 } 1817 }
1811 } 1818 }
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 7ca2ae45b2d5..e14c33b42f75 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -126,7 +126,6 @@ struct net_bridge_mdb_entry
126 struct timer_list timer; 126 struct timer_list timer;
127 struct br_ip addr; 127 struct br_ip addr;
128 bool mglist; 128 bool mglist;
129 bool timer_armed;
130}; 129};
131 130
132struct net_bridge_mdb_htable 131struct net_bridge_mdb_htable