Skip to content

Commit

Permalink
bridge: only expire the mdb entry when query is received
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Cong Wang authored and davem330 committed May 22, 2013
1 parent 1c8ad5b commit 9f00b2e
Show file tree
Hide file tree
Showing 2 changed files with 13 additions and 27 deletions.
39 changes: 12 additions & 27 deletions net/bridge/br_multicast.c
Original file line number Diff line number Diff line change
Expand Up @@ -617,8 +617,6 @@ struct net_bridge_mdb_entry *br_multicast_new_group(struct net_bridge *br,

mp->br = br;
mp->addr = *group;
setup_timer(&mp->timer, br_multicast_group_expired,
(unsigned long)mp);

hlist_add_head_rcu(&mp->hlist[mdb->ver], &mdb->mhash[hash]);
mdb->size++;
Expand Down Expand Up @@ -656,7 +654,6 @@ static int br_multicast_add_group(struct net_bridge *br,
struct net_bridge_mdb_entry *mp;
struct net_bridge_port_group *p;
struct net_bridge_port_group __rcu **pp;
unsigned long now = jiffies;
int err;

spin_lock(&br->multicast_lock);
Expand All @@ -671,15 +668,14 @@ static int br_multicast_add_group(struct net_bridge *br,

if (!port) {
mp->mglist = true;
mod_timer(&mp->timer, now + br->multicast_membership_interval);
goto out;
}

for (pp = &mp->ports;
(p = mlock_dereference(*pp, br)) != NULL;
pp = &p->next) {
if (p->port == port)
goto found;
goto out;
if ((unsigned long)p->port < (unsigned long)port)
break;
}
Expand All @@ -690,8 +686,6 @@ static int br_multicast_add_group(struct net_bridge *br,
rcu_assign_pointer(*pp, p);
br_mdb_notify(br->dev, port, group, RTM_NEWMDB);

found:
mod_timer(&p->timer, now + br->multicast_membership_interval);
out:
err = 0;

Expand Down Expand Up @@ -1131,6 +1125,10 @@ static int br_ip4_multicast_query(struct net_bridge *br,
if (!mp)
goto out;

setup_timer(&mp->timer, br_multicast_group_expired, (unsigned long)mp);
mod_timer(&mp->timer, now + br->multicast_membership_interval);
mp->timer_armed = true;

max_delay *= br->multicast_last_member_count;

if (mp->mglist &&
Expand Down Expand Up @@ -1205,6 +1203,10 @@ static int br_ip6_multicast_query(struct net_bridge *br,
if (!mp)
goto out;

setup_timer(&mp->timer, br_multicast_group_expired, (unsigned long)mp);
mod_timer(&mp->timer, now + br->multicast_membership_interval);
mp->timer_armed = true;

max_delay *= br->multicast_last_member_count;
if (mp->mglist &&
(timer_pending(&mp->timer) ?
Expand Down Expand Up @@ -1263,7 +1265,7 @@ static void br_multicast_leave_group(struct net_bridge *br,
call_rcu_bh(&p->rcu, br_multicast_free_pg);
br_mdb_notify(br->dev, port, group, RTM_DELMDB);

if (!mp->ports && !mp->mglist &&
if (!mp->ports && !mp->mglist && mp->timer_armed &&
netif_running(br->dev))
mod_timer(&mp->timer, jiffies);
}
Expand All @@ -1275,30 +1277,12 @@ static void br_multicast_leave_group(struct net_bridge *br,
br->multicast_last_member_interval;

if (!port) {
if (mp->mglist &&
if (mp->mglist && mp->timer_armed &&
(timer_pending(&mp->timer) ?
time_after(mp->timer.expires, time) :
try_to_del_timer_sync(&mp->timer) >= 0)) {
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:
Expand Down Expand Up @@ -1674,6 +1658,7 @@ void br_multicast_stop(struct net_bridge *br)
hlist_for_each_entry_safe(mp, n, &mdb->mhash[i],
hlist[ver]) {
del_timer(&mp->timer);
mp->timer_armed = false;
call_rcu_bh(&mp->rcu, br_multicast_free_group);
}
}
Expand Down
1 change: 1 addition & 0 deletions net/bridge/br_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ struct net_bridge_mdb_entry
struct timer_list timer;
struct br_ip addr;
bool mglist;
bool timer_armed;
};

struct net_bridge_mdb_htable
Expand Down

0 comments on commit 9f00b2e

Please sign in to comment.