160 lines
4.8 KiB
Diff
160 lines
4.8 KiB
Diff
|
From 9f00b2e7cf241fa389733d41b615efdaa2cb0f5b Mon Sep 17 00:00:00 2001
|
||
|
From: Cong Wang <amwang@redhat.com>
|
||
|
Date: Tue, 21 May 2013 21:52:55 +0000
|
||
|
Subject: 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: Cong Wang <amwang@redhat.com>
|
||
|
Acked-by: Herbert Xu <herbert@gondor.apana.org.au>
|
||
|
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||
|
---
|
||
|
(limited to 'net/bridge')
|
||
|
|
||
|
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
|
||
|
index 2475147..40bda80 100644
|
||
|
--- a/net/bridge/br_multicast.c
|
||
|
+++ b/net/bridge/br_multicast.c
|
||
|
@@ -617,8 +617,6 @@ rehash:
|
||
|
|
||
|
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++;
|
||
|
@@ -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);
|
||
|
@@ -671,7 +668,6 @@ 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;
|
||
|
}
|
||
|
|
||
|
@@ -679,7 +675,7 @@ static int br_multicast_add_group(struct net_bridge *br,
|
||
|
(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;
|
||
|
}
|
||
|
@@ -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;
|
||
|
|
||
|
@@ -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 &&
|
||
|
@@ -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) ?
|
||
|
@@ -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);
|
||
|
}
|
||
|
@@ -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:
|
||
|
@@ -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);
|
||
|
}
|
||
|
}
|
||
|
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
|
||
|
index e260710..1b0ac95 100644
|
||
|
--- a/net/bridge/br_private.h
|
||
|
+++ b/net/bridge/br_private.h
|
||
|
@@ -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
|
||
|
--
|
||
|
cgit v0.9.2
|