summaryrefslogtreecommitdiffstats
path: root/bridge-only-expire-the-mdb-entry-when-query-is-received.patch
diff options
context:
space:
mode:
authorJosh Boyer <jwboyer@redhat.com>2013-06-26 07:50:55 -0400
committerJosh Boyer <jwboyer@redhat.com>2013-06-26 07:51:29 -0400
commit69c0bf478219b2fbb38fb3c707b220b75bfa4129 (patch)
tree05c8bb10cd71353428b266b9078c40c5c4adb01d /bridge-only-expire-the-mdb-entry-when-query-is-received.patch
parent0a517e3c24f320b2b6336a3413fd9884bc36c954 (diff)
downloadkernel-69c0bf478219b2fbb38fb3c707b220b75bfa4129.tar.gz
kernel-69c0bf478219b2fbb38fb3c707b220b75bfa4129.tar.xz
kernel-69c0bf478219b2fbb38fb3c707b220b75bfa4129.zip
Add two patches to fix bridge networking issues (rhbz 880035)
Diffstat (limited to 'bridge-only-expire-the-mdb-entry-when-query-is-received.patch')
-rw-r--r--bridge-only-expire-the-mdb-entry-when-query-is-received.patch159
1 files changed, 159 insertions, 0 deletions
diff --git a/bridge-only-expire-the-mdb-entry-when-query-is-received.patch b/bridge-only-expire-the-mdb-entry-when-query-is-received.patch
new file mode 100644
index 000000000..b58b57083
--- /dev/null
+++ b/bridge-only-expire-the-mdb-entry-when-query-is-received.patch
@@ -0,0 +1,159 @@
+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