Commit 454594f3 authored by Linus Lüssing's avatar Linus Lüssing Committed by David S. Miller

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" (b00589af)
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 f144febd.
Revert "bridge: do not call setup_timer() multiple times"
This reverts commit 1faabf2a.
Revert "bridge: fix some kernel warning in multicast timer"
This reverts commit c7e8e8a8.
Revert "bridge: only expire the mdb entry when query is received"
This reverts commit 9f00b2e7.
====================

CC: Cong Wang <amwang@redhat.com>
Signed-off-by: default avatarLinus Lüssing <linus.luessing@web.de>
Reviewed-by: default avatarVlad Yasevich <vyasevich@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 02cf4ebd
...@@ -453,7 +453,7 @@ static int __br_mdb_del(struct net_bridge *br, struct br_mdb_entry *entry) ...@@ -453,7 +453,7 @@ static int __br_mdb_del(struct net_bridge *br, struct br_mdb_entry *entry)
call_rcu_bh(&p->rcu, br_multicast_free_pg); call_rcu_bh(&p->rcu, br_multicast_free_pg);
err = 0; err = 0;
if (!mp->ports && !mp->mglist && mp->timer_armed && if (!mp->ports && !mp->mglist &&
netif_running(br->dev)) netif_running(br->dev))
mod_timer(&mp->timer, jiffies); mod_timer(&mp->timer, jiffies);
break; break;
......
...@@ -272,7 +272,7 @@ static void br_multicast_del_pg(struct net_bridge *br, ...@@ -272,7 +272,7 @@ static void br_multicast_del_pg(struct net_bridge *br,
del_timer(&p->timer); del_timer(&p->timer);
call_rcu_bh(&p->rcu, br_multicast_free_pg); call_rcu_bh(&p->rcu, br_multicast_free_pg);
if (!mp->ports && !mp->mglist && mp->timer_armed && if (!mp->ports && !mp->mglist &&
netif_running(br->dev)) netif_running(br->dev))
mod_timer(&mp->timer, jiffies); mod_timer(&mp->timer, jiffies);
...@@ -611,9 +611,6 @@ struct net_bridge_mdb_entry *br_multicast_new_group(struct net_bridge *br, ...@@ -611,9 +611,6 @@ struct net_bridge_mdb_entry *br_multicast_new_group(struct net_bridge *br,
break; break;
default: default:
/* If we have an existing entry, update it's expire timer */
mod_timer(&mp->timer,
jiffies + br->multicast_membership_interval);
goto out; goto out;
} }
...@@ -623,7 +620,6 @@ struct net_bridge_mdb_entry *br_multicast_new_group(struct net_bridge *br, ...@@ -623,7 +620,6 @@ struct net_bridge_mdb_entry *br_multicast_new_group(struct net_bridge *br,
mp->br = br; mp->br = br;
mp->addr = *group; mp->addr = *group;
setup_timer(&mp->timer, br_multicast_group_expired, setup_timer(&mp->timer, br_multicast_group_expired,
(unsigned long)mp); (unsigned long)mp);
...@@ -663,6 +659,7 @@ static int br_multicast_add_group(struct net_bridge *br, ...@@ -663,6 +659,7 @@ static int br_multicast_add_group(struct net_bridge *br,
struct net_bridge_mdb_entry *mp; struct net_bridge_mdb_entry *mp;
struct net_bridge_port_group *p; struct net_bridge_port_group *p;
struct net_bridge_port_group __rcu **pp; struct net_bridge_port_group __rcu **pp;
unsigned long now = jiffies;
int err; int err;
spin_lock(&br->multicast_lock); spin_lock(&br->multicast_lock);
...@@ -677,18 +674,15 @@ static int br_multicast_add_group(struct net_bridge *br, ...@@ -677,18 +674,15 @@ static int br_multicast_add_group(struct net_bridge *br,
if (!port) { if (!port) {
mp->mglist = true; mp->mglist = true;
mod_timer(&mp->timer, now + br->multicast_membership_interval);
goto out; goto out;
} }
for (pp = &mp->ports; for (pp = &mp->ports;
(p = mlock_dereference(*pp, br)) != NULL; (p = mlock_dereference(*pp, br)) != NULL;
pp = &p->next) { pp = &p->next) {
if (p->port == port) { if (p->port == port)
/* We already have a portgroup, update the timer. */ goto found;
mod_timer(&p->timer,
jiffies + br->multicast_membership_interval);
goto out;
}
if ((unsigned long)p->port < (unsigned long)port) if ((unsigned long)p->port < (unsigned long)port)
break; break;
} }
...@@ -699,6 +693,8 @@ static int br_multicast_add_group(struct net_bridge *br, ...@@ -699,6 +693,8 @@ static int br_multicast_add_group(struct net_bridge *br,
rcu_assign_pointer(*pp, p); rcu_assign_pointer(*pp, p);
br_mdb_notify(br->dev, port, group, RTM_NEWMDB); br_mdb_notify(br->dev, port, group, RTM_NEWMDB);
found:
mod_timer(&p->timer, now + br->multicast_membership_interval);
out: out:
err = 0; err = 0;
...@@ -1198,9 +1194,6 @@ static int br_ip4_multicast_query(struct net_bridge *br, ...@@ -1198,9 +1194,6 @@ static int br_ip4_multicast_query(struct net_bridge *br,
if (!mp) if (!mp)
goto out; goto out;
mod_timer(&mp->timer, now + br->multicast_membership_interval);
mp->timer_armed = true;
max_delay *= br->multicast_last_member_count; max_delay *= br->multicast_last_member_count;
if (mp->mglist && if (mp->mglist &&
...@@ -1277,9 +1270,6 @@ static int br_ip6_multicast_query(struct net_bridge *br, ...@@ -1277,9 +1270,6 @@ static int br_ip6_multicast_query(struct net_bridge *br,
if (!mp) if (!mp)
goto out; goto out;
mod_timer(&mp->timer, now + br->multicast_membership_interval);
mp->timer_armed = true;
max_delay *= br->multicast_last_member_count; max_delay *= br->multicast_last_member_count;
if (mp->mglist && if (mp->mglist &&
(timer_pending(&mp->timer) ? (timer_pending(&mp->timer) ?
...@@ -1365,7 +1355,7 @@ static void br_multicast_leave_group(struct net_bridge *br, ...@@ -1365,7 +1355,7 @@ static void br_multicast_leave_group(struct net_bridge *br,
call_rcu_bh(&p->rcu, br_multicast_free_pg); call_rcu_bh(&p->rcu, br_multicast_free_pg);
br_mdb_notify(br->dev, port, group, RTM_DELMDB); br_mdb_notify(br->dev, port, group, RTM_DELMDB);
if (!mp->ports && !mp->mglist && mp->timer_armed && if (!mp->ports && !mp->mglist &&
netif_running(br->dev)) netif_running(br->dev))
mod_timer(&mp->timer, jiffies); mod_timer(&mp->timer, jiffies);
} }
...@@ -1377,12 +1367,30 @@ static void br_multicast_leave_group(struct net_bridge *br, ...@@ -1377,12 +1367,30 @@ static void br_multicast_leave_group(struct net_bridge *br,
br->multicast_last_member_interval; br->multicast_last_member_interval;
if (!port) { if (!port) {
if (mp->mglist && mp->timer_armed && if (mp->mglist &&
(timer_pending(&mp->timer) ? (timer_pending(&mp->timer) ?
time_after(mp->timer.expires, time) : time_after(mp->timer.expires, time) :
try_to_del_timer_sync(&mp->timer) >= 0)) { try_to_del_timer_sync(&mp->timer) >= 0)) {
mod_timer(&mp->timer, time); mod_timer(&mp->timer, time);
} }
goto out;
}
for (p = mlock_dereference(mp->ports, br);
p != NULL;
p = mlock_dereference(p->next, br)) {
if (p->port != port)
continue;
if (!hlist_unhashed(&p->mglist) &&
(timer_pending(&p->timer) ?
time_after(p->timer.expires, time) :
try_to_del_timer_sync(&p->timer) >= 0)) {
mod_timer(&p->timer, time);
}
break;
} }
out: out:
spin_unlock(&br->multicast_lock); spin_unlock(&br->multicast_lock);
...@@ -1805,7 +1813,6 @@ void br_multicast_stop(struct net_bridge *br) ...@@ -1805,7 +1813,6 @@ void br_multicast_stop(struct net_bridge *br)
hlist_for_each_entry_safe(mp, n, &mdb->mhash[i], hlist_for_each_entry_safe(mp, n, &mdb->mhash[i],
hlist[ver]) { hlist[ver]) {
del_timer(&mp->timer); del_timer(&mp->timer);
mp->timer_armed = false;
call_rcu_bh(&mp->rcu, br_multicast_free_group); call_rcu_bh(&mp->rcu, br_multicast_free_group);
} }
} }
......
...@@ -126,7 +126,6 @@ struct net_bridge_mdb_entry ...@@ -126,7 +126,6 @@ struct net_bridge_mdb_entry
struct timer_list timer; struct timer_list timer;
struct br_ip addr; struct br_ip addr;
bool mglist; bool mglist;
bool timer_armed;
}; };
struct net_bridge_mdb_htable struct net_bridge_mdb_htable
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment