提交 9f00b2e7 编写于 作者: C Cong Wang 提交者: David S. Miller

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: NCong Wang <amwang@redhat.com>
Acked-by: NHerbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
上级 1c8ad5bf
...@@ -617,8 +617,6 @@ struct net_bridge_mdb_entry *br_multicast_new_group(struct net_bridge *br, ...@@ -617,8 +617,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,
(unsigned long)mp);
hlist_add_head_rcu(&mp->hlist[mdb->ver], &mdb->mhash[hash]); hlist_add_head_rcu(&mp->hlist[mdb->ver], &mdb->mhash[hash]);
mdb->size++; mdb->size++;
...@@ -656,7 +654,6 @@ static int br_multicast_add_group(struct net_bridge *br, ...@@ -656,7 +654,6 @@ 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);
...@@ -671,7 +668,6 @@ static int br_multicast_add_group(struct net_bridge *br, ...@@ -671,7 +668,6 @@ 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;
} }
...@@ -679,7 +675,7 @@ static int br_multicast_add_group(struct net_bridge *br, ...@@ -679,7 +675,7 @@ static int br_multicast_add_group(struct net_bridge *br,
(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)
goto found; goto out;
if ((unsigned long)p->port < (unsigned long)port) if ((unsigned long)p->port < (unsigned long)port)
break; break;
} }
...@@ -690,8 +686,6 @@ static int br_multicast_add_group(struct net_bridge *br, ...@@ -690,8 +686,6 @@ 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;
...@@ -1131,6 +1125,10 @@ static int br_ip4_multicast_query(struct net_bridge *br, ...@@ -1131,6 +1125,10 @@ static int br_ip4_multicast_query(struct net_bridge *br,
if (!mp) if (!mp)
goto out; 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; max_delay *= br->multicast_last_member_count;
if (mp->mglist && if (mp->mglist &&
...@@ -1205,6 +1203,10 @@ static int br_ip6_multicast_query(struct net_bridge *br, ...@@ -1205,6 +1203,10 @@ static int br_ip6_multicast_query(struct net_bridge *br,
if (!mp) if (!mp)
goto out; 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; max_delay *= br->multicast_last_member_count;
if (mp->mglist && if (mp->mglist &&
(timer_pending(&mp->timer) ? (timer_pending(&mp->timer) ?
...@@ -1263,7 +1265,7 @@ static void br_multicast_leave_group(struct net_bridge *br, ...@@ -1263,7 +1265,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 && if (!mp->ports && !mp->mglist && mp->timer_armed &&
netif_running(br->dev)) netif_running(br->dev))
mod_timer(&mp->timer, jiffies); mod_timer(&mp->timer, jiffies);
} }
...@@ -1275,30 +1277,12 @@ static void br_multicast_leave_group(struct net_bridge *br, ...@@ -1275,30 +1277,12 @@ 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 && if (mp->mglist && mp->timer_armed &&
(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:
...@@ -1674,6 +1658,7 @@ void br_multicast_stop(struct net_bridge *br) ...@@ -1674,6 +1658,7 @@ 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);
} }
} }
......
...@@ -112,6 +112,7 @@ struct net_bridge_mdb_entry ...@@ -112,6 +112,7 @@ 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% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册