diff options
author | Linus Lüssing <linus.luessing@web.de> | 2013-10-19 18:58:57 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-10-22 14:41:02 -0400 |
commit | 454594f3b93a49ef568cd190c5af31376b105a7b (patch) | |
tree | 5a3109ffdd29aed110e7cd5e4295dfe0246595fd /net | |
parent | 02cf4ebd82ff0ac7254b88e466820a290ed8289a (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.c | 2 | ||||
-rw-r--r-- | net/bridge/br_multicast.c | 47 | ||||
-rw-r--r-- | net/bridge/br_private.h | 1 |
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 | ||
696 | found: | ||
697 | mod_timer(&p->timer, now + br->multicast_membership_interval); | ||
702 | out: | 698 | out: |
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 | } |
1387 | out: | 1395 | out: |
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 | ||
132 | struct net_bridge_mdb_htable | 131 | struct net_bridge_mdb_htable |