Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756633Ab3HZKBd (ORCPT ); Mon, 26 Aug 2013 06:01:33 -0400 Received: from mout.web.de ([212.227.15.14]:62181 "EHLO mout.web.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756340Ab3HZKBX (ORCPT ); Mon, 26 Aug 2013 06:01:23 -0400 From: =?UTF-8?q?Linus=20L=C3=BCssing?= To: bridge@lists.linux-foundation.org Cc: Stephen Hemminger , "David S. Miller" , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, Herbert Xu , Cong Wang , Adam Baker , =?UTF-8?q?Linus=20L=C3=BCssing?= Subject: [PATCH] bridge: separate querier and query timer into IGMP/IPv4 and MLD/IPv6 ones Date: Mon, 26 Aug 2013 12:01:06 +0200 Message-Id: <1377511266-14530-1-git-send-email-linus.luessing@web.de> X-Mailer: git-send-email 1.8.4.rc3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Provags-ID: V03:K0:AGsL6CkfKlLf0abtpa6GeUl3bLCnIpBHtELT8vdUV6MGxOIcD2o rMbnSA5T0/kHQkias7wnNI9tYhEvmNtcMzegcZtyHAIf0ijOkeI1uRWalzTUFC6JFBS4ypI 1BeH11Wk4yw7meRK9y2JM3bVR3pEX76DD4F6mnadaYRszJ9g8iVR0mUHrxRwUjD4U30qZ19 vFuDOe52/2+IBknXcU5+Q== Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 24952 Lines: 783 Currently we would still potentially suffer multicast packet loss if there is just either an IGMP or an MLD querier: For the former case, we would possibly drop IPv6 multicast packets, for the latter IPv4 ones. This is because we are currently assuming that if either an IGMP or MLD querier is present that the other one is present, too. This patch makes the behaviour and fix added in "bridge: disable snooping if there is no querier" (b00589af3b04) to also work if there is either just an IGMP or an MLD querier on the link: It refines the deactivation of the snooping to be protocol specific by using separate timers for the snooped IGMP and MLD queries as well as separate timers for our internal IGMP and MLD queriers. Signed-off-by: Linus Lüssing --- net/bridge/br_device.c | 2 +- net/bridge/br_input.c | 2 +- net/bridge/br_mdb.c | 14 +- net/bridge/br_multicast.c | 338 +++++++++++++++++++++++++++++++++++---------- net/bridge/br_private.h | 47 +++++-- 5 files changed, 313 insertions(+), 90 deletions(-) diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c index 69363bd..89659d4 100644 --- a/net/bridge/br_device.c +++ b/net/bridge/br_device.c @@ -71,7 +71,7 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev) mdst = br_mdb_get(br, skb, vid); if ((mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) && - br_multicast_querier_exists(br)) + br_multicast_querier_exists(br, eth_hdr(skb))) br_multicast_deliver(mdst, skb); else br_flood_deliver(br, skb, false); diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c index 8c561c0..a2fd37e 100644 --- a/net/bridge/br_input.c +++ b/net/bridge/br_input.c @@ -102,7 +102,7 @@ int br_handle_frame_finish(struct sk_buff *skb) } else if (is_multicast_ether_addr(dest)) { mdst = br_mdb_get(br, skb, vid); if ((mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) && - br_multicast_querier_exists(br)) { + br_multicast_querier_exists(br, eth_hdr(skb))) { if ((mdst && mdst->mglist) || br_multicast_is_router(br)) skb2 = skb; diff --git a/net/bridge/br_mdb.c b/net/bridge/br_mdb.c index 0daae3e..6053b96 100644 --- a/net/bridge/br_mdb.c +++ b/net/bridge/br_mdb.c @@ -414,16 +414,20 @@ static int __br_mdb_del(struct net_bridge *br, struct br_mdb_entry *entry) if (!netif_running(br->dev) || br->multicast_disabled) return -EINVAL; - if (timer_pending(&br->multicast_querier_timer)) - return -EBUSY; - ip.proto = entry->addr.proto; - if (ip.proto == htons(ETH_P_IP)) + if (ip.proto == htons(ETH_P_IP)) { + if (timer_pending(&br->ip4_multicast_querier_timer)) + return -EBUSY; + ip.u.ip4 = entry->addr.u.ip4; #if IS_ENABLED(CONFIG_IPV6) - else + } else { + if (timer_pending(&br->ip6_multicast_querier_timer)) + return -EBUSY; + ip.u.ip6 = entry->addr.u.ip6; #endif + } spin_lock_bh(&br->multicast_lock); mdb = mlock_dereference(br->mdb, br); diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index 08e576a..e1c01f4 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c @@ -33,7 +33,10 @@ #include "br_private.h" -static void br_multicast_start_querier(struct net_bridge *br); +static void br_ip4_multicast_start_querier(struct net_bridge *br); +#if IS_ENABLED(CONFIG_IPV6) +static void br_ip6_multicast_start_querier(struct net_bridge *br); +#endif unsigned int br_mdb_rehash_seq; static inline int br_ip_equal(const struct br_ip *a, const struct br_ip *b) @@ -755,7 +758,22 @@ static void br_multicast_local_router_expired(unsigned long data) { } -static void br_multicast_querier_expired(unsigned long data) +static void br_ip4_multicast_querier_expired(unsigned long data) +{ + struct net_bridge *br = (void *)data; + + spin_lock(&br->multicast_lock); + if (!netif_running(br->dev) || br->multicast_disabled) + goto out; + + br_ip4_multicast_start_querier(br); + +out: + spin_unlock(&br->multicast_lock); +} + +#if IS_ENABLED(CONFIG_IPV6) +static void br_ip6_multicast_querier_expired(unsigned long data) { struct net_bridge *br = (void *)data; @@ -763,11 +781,12 @@ static void br_multicast_querier_expired(unsigned long data) if (!netif_running(br->dev) || br->multicast_disabled) goto out; - br_multicast_start_querier(br); + br_ip6_multicast_start_querier(br); out: spin_unlock(&br->multicast_lock); } +#endif static void __br_multicast_send_query(struct net_bridge *br, struct net_bridge_port *port, @@ -788,15 +807,15 @@ static void __br_multicast_send_query(struct net_bridge *br, netif_rx(skb); } -static void br_multicast_send_query(struct net_bridge *br, - struct net_bridge_port *port, u32 sent) +static void br_ip4_multicast_send_query(struct net_bridge *br, + struct net_bridge_port *port, u32 sent) { unsigned long time; struct br_ip br_group; if (!netif_running(br->dev) || br->multicast_disabled || !br->multicast_querier || - timer_pending(&br->multicast_querier_timer)) + timer_pending(&br->ip4_multicast_querier_timer)) return; memset(&br_group.u, 0, sizeof(br_group.u)); @@ -804,20 +823,41 @@ static void br_multicast_send_query(struct net_bridge *br, br_group.proto = htons(ETH_P_IP); __br_multicast_send_query(br, port, &br_group); + time = jiffies; + time += sent < br->multicast_startup_query_count ? + br->multicast_startup_query_interval : + br->multicast_query_interval; + mod_timer(port ? &port->ip4_multicast_query_timer : + &br->ip4_multicast_query_timer, time); +} + #if IS_ENABLED(CONFIG_IPV6) +static void br_ip6_multicast_send_query(struct net_bridge *br, + struct net_bridge_port *port, u32 sent) +{ + unsigned long time; + struct br_ip br_group; + + if (!netif_running(br->dev) || br->multicast_disabled || + !br->multicast_querier || + timer_pending(&br->ip6_multicast_querier_timer)) + return; + + memset(&br_group.u, 0, sizeof(br_group.u)); + br_group.proto = htons(ETH_P_IPV6); __br_multicast_send_query(br, port, &br_group); -#endif time = jiffies; time += sent < br->multicast_startup_query_count ? br->multicast_startup_query_interval : br->multicast_query_interval; - mod_timer(port ? &port->multicast_query_timer : - &br->multicast_query_timer, time); + mod_timer(port ? &port->ip6_multicast_query_timer : + &br->ip6_multicast_query_timer, time); } +#endif -static void br_multicast_port_query_expired(unsigned long data) +static void br_ip4_multicast_port_query_expired(unsigned long data) { struct net_bridge_port *port = (void *)data; struct net_bridge *br = port->br; @@ -827,25 +867,52 @@ static void br_multicast_port_query_expired(unsigned long data) port->state == BR_STATE_BLOCKING) goto out; - if (port->multicast_startup_queries_sent < + if (port->ip4_multicast_startup_queries_sent < br->multicast_startup_query_count) - port->multicast_startup_queries_sent++; + port->ip4_multicast_startup_queries_sent++; - br_multicast_send_query(port->br, port, - port->multicast_startup_queries_sent); + br_ip4_multicast_send_query(port->br, port, + port->ip4_multicast_startup_queries_sent); out: spin_unlock(&br->multicast_lock); } +#if IS_ENABLED(CONFIG_IPV6) +static void br_ip6_multicast_port_query_expired(unsigned long data) +{ + struct net_bridge_port *port = (void *)data; + struct net_bridge *br = port->br; + + spin_lock(&br->multicast_lock); + if (port->state == BR_STATE_DISABLED || + port->state == BR_STATE_BLOCKING) + goto out; + + if (port->ip6_multicast_startup_queries_sent < + br->multicast_startup_query_count) + port->ip6_multicast_startup_queries_sent++; + + br_ip6_multicast_send_query(port->br, port, + port->ip6_multicast_startup_queries_sent); + +out: + spin_unlock(&br->multicast_lock); +} +#endif + void br_multicast_add_port(struct net_bridge_port *port) { port->multicast_router = 1; setup_timer(&port->multicast_router_timer, br_multicast_router_expired, (unsigned long)port); - setup_timer(&port->multicast_query_timer, - br_multicast_port_query_expired, (unsigned long)port); + setup_timer(&port->ip4_multicast_query_timer, + br_ip4_multicast_port_query_expired, (unsigned long)port); +#if IS_ENABLED(CONFIG_IPV6) + setup_timer(&port->ip6_multicast_query_timer, + br_ip6_multicast_port_query_expired, (unsigned long)port); +#endif } void br_multicast_del_port(struct net_bridge_port *port) @@ -853,14 +920,25 @@ void br_multicast_del_port(struct net_bridge_port *port) del_timer_sync(&port->multicast_router_timer); } -static void __br_multicast_enable_port(struct net_bridge_port *port) +static void __br_ip4_multicast_enable_port(struct net_bridge_port *port) +{ + port->ip4_multicast_startup_queries_sent = 0; + + if (try_to_del_timer_sync(&port->ip4_multicast_query_timer) >= 0 || + del_timer(&port->ip4_multicast_query_timer)) + mod_timer(&port->ip4_multicast_query_timer, jiffies); +} + +#if IS_ENABLED(CONFIG_IPV6) +static void __br_ip6_multicast_enable_port(struct net_bridge_port *port) { - port->multicast_startup_queries_sent = 0; + port->ip6_multicast_startup_queries_sent = 0; - if (try_to_del_timer_sync(&port->multicast_query_timer) >= 0 || - del_timer(&port->multicast_query_timer)) - mod_timer(&port->multicast_query_timer, jiffies); + if (try_to_del_timer_sync(&port->ip6_multicast_query_timer) >= 0 || + del_timer(&port->ip6_multicast_query_timer)) + mod_timer(&port->ip6_multicast_query_timer, jiffies); } +#endif void br_multicast_enable_port(struct net_bridge_port *port) { @@ -870,7 +948,10 @@ void br_multicast_enable_port(struct net_bridge_port *port) if (br->multicast_disabled || !netif_running(br->dev)) goto out; - __br_multicast_enable_port(port); + __br_ip4_multicast_enable_port(port); +#if IS_ENABLED(CONFIG_IPV6) + __br_ip6_multicast_enable_port(port); +#endif out: spin_unlock(&br->multicast_lock); @@ -889,7 +970,8 @@ void br_multicast_disable_port(struct net_bridge_port *port) if (!hlist_unhashed(&port->rlist)) hlist_del_init_rcu(&port->rlist); del_timer(&port->multicast_router_timer); - del_timer(&port->multicast_query_timer); + del_timer(&port->ip4_multicast_query_timer); + del_timer(&port->ip6_multicast_query_timer); spin_unlock(&br->multicast_lock); } @@ -1014,16 +1096,28 @@ static int br_ip6_multicast_mld2_report(struct net_bridge *br, } #endif -static void br_multicast_update_querier_timer(struct net_bridge *br, - unsigned long max_delay) +static void br_ip4_multicast_update_querier_timer(struct net_bridge *br, + unsigned long max_delay) { - if (!timer_pending(&br->multicast_querier_timer)) - br->multicast_querier_delay_time = jiffies + max_delay; + if (!timer_pending(&br->ip4_multicast_querier_timer)) + br->ip4_multicast_querier_delay_time = jiffies + max_delay; - mod_timer(&br->multicast_querier_timer, + mod_timer(&br->ip4_multicast_querier_timer, jiffies + br->multicast_querier_interval); } +#if IS_ENABLED(CONFIG_IPV6) +static void br_ip6_multicast_update_querier_timer(struct net_bridge *br, + unsigned long max_delay) +{ + if (!timer_pending(&br->ip6_multicast_querier_timer)) + br->ip6_multicast_querier_delay_time = jiffies + max_delay; + + mod_timer(&br->ip6_multicast_querier_timer, + jiffies + br->multicast_querier_interval); +} +#endif + /* * Add port to router_list * list is maintained ordered by pointer value @@ -1072,18 +1166,33 @@ timer: now + br->multicast_querier_interval); } -static void br_multicast_query_received(struct net_bridge *br, - struct net_bridge_port *port, - int saddr, - unsigned long max_delay) +static void br_ip4_multicast_query_received(struct net_bridge *br, + struct net_bridge_port *port, + int saddr, + unsigned long max_delay) +{ + if (saddr) + br_ip4_multicast_update_querier_timer(br, max_delay); + else if (timer_pending(&br->ip4_multicast_querier_timer)) + return; + + br_multicast_mark_router(br, port); +} + +#if IS_ENABLED(CONFIG_IPV6) +static void br_ip6_multicast_query_received(struct net_bridge *br, + struct net_bridge_port *port, + int saddr, + unsigned long max_delay) { if (saddr) - br_multicast_update_querier_timer(br, max_delay); - else if (timer_pending(&br->multicast_querier_timer)) + br_ip6_multicast_update_querier_timer(br, max_delay); + else if (timer_pending(&br->ip6_multicast_querier_timer)) return; br_multicast_mark_router(br, port); } +#endif static int br_ip4_multicast_query(struct net_bridge *br, struct net_bridge_port *port, @@ -1129,7 +1238,7 @@ static int br_ip4_multicast_query(struct net_bridge *br, IGMPV3_MRC(ih3->code) * (HZ / IGMP_TIMER_SCALE) : 1; } - br_multicast_query_received(br, port, !!iph->saddr, max_delay); + br_ip4_multicast_query_received(br, port, !!iph->saddr, max_delay); if (!group) goto out; @@ -1206,8 +1315,8 @@ static int br_ip6_multicast_query(struct net_bridge *br, max_delay = mld2q->mld2q_mrc ? MLDV2_MRC(ntohs(mld2q->mld2q_mrc)) : 1; } - br_multicast_query_received(br, port, !ipv6_addr_any(&ip6h->saddr), - max_delay); + br_ip6_multicast_query_received(br, port, !ipv6_addr_any(&ip6h->saddr), + max_delay); if (!group) goto out; @@ -1252,25 +1361,23 @@ static void br_multicast_leave_group(struct net_bridge *br, unsigned long now; unsigned long time; - spin_lock(&br->multicast_lock); - if (!netif_running(br->dev) || - (port && port->state == BR_STATE_DISABLED) || - timer_pending(&br->multicast_querier_timer)) - goto out; - mdb = mlock_dereference(br->mdb, br); mp = br_mdb_ip_get(mdb, group); if (!mp) - goto out; + return; - if (br->multicast_querier && - !timer_pending(&br->multicast_querier_timer)) { + if (br->multicast_querier) { __br_multicast_send_query(br, port, &mp->addr); time = jiffies + br->multicast_last_member_count * br->multicast_last_member_interval; - mod_timer(port ? &port->multicast_query_timer : - &br->multicast_query_timer, time); + + if (group->proto == htons(ETH_P_IP)) + mod_timer(port ? &port->ip4_multicast_query_timer : + &br->ip4_multicast_query_timer, time); + else + mod_timer(port ? &port->ip6_multicast_query_timer : + &br->ip6_multicast_query_timer, time); for (p = mlock_dereference(mp->ports, br); p != NULL; @@ -1308,7 +1415,7 @@ static void br_multicast_leave_group(struct net_bridge *br, netif_running(br->dev)) mod_timer(&mp->timer, jiffies); } - goto out; + return; } now = jiffies; @@ -1323,9 +1430,6 @@ static void br_multicast_leave_group(struct net_bridge *br, mod_timer(&mp->timer, time); } } - -out: - spin_unlock(&br->multicast_lock); } static void br_ip4_multicast_leave_group(struct net_bridge *br, @@ -1342,7 +1446,15 @@ static void br_ip4_multicast_leave_group(struct net_bridge *br, br_group.proto = htons(ETH_P_IP); br_group.vid = vid; + spin_lock(&br->multicast_lock); + if (!netif_running(br->dev) || + (port && port->state == BR_STATE_DISABLED) || + timer_pending(&br->ip4_multicast_querier_timer)) + goto out; + br_multicast_leave_group(br, port, &br_group); +out: + spin_unlock(&br->multicast_lock); } #if IS_ENABLED(CONFIG_IPV6) @@ -1360,7 +1472,15 @@ static void br_ip6_multicast_leave_group(struct net_bridge *br, br_group.proto = htons(ETH_P_IPV6); br_group.vid = vid; + spin_lock(&br->multicast_lock); + if (!netif_running(br->dev) || + (port && port->state == BR_STATE_DISABLED) || + timer_pending(&br->ip6_multicast_querier_timer)) + goto out; + br_multicast_leave_group(br, port, &br_group); +out: + spin_unlock(&br->multicast_lock); } #endif @@ -1622,20 +1742,38 @@ int br_multicast_rcv(struct net_bridge *br, struct net_bridge_port *port, return 0; } -static void br_multicast_query_expired(unsigned long data) +static void br_ip4_multicast_query_expired(unsigned long data) { struct net_bridge *br = (void *)data; spin_lock(&br->multicast_lock); - if (br->multicast_startup_queries_sent < + if (br->ip4_multicast_startup_queries_sent < br->multicast_startup_query_count) - br->multicast_startup_queries_sent++; + br->ip4_multicast_startup_queries_sent++; - br_multicast_send_query(br, NULL, br->multicast_startup_queries_sent); + br_ip4_multicast_send_query(br, NULL, + br->ip4_multicast_startup_queries_sent); spin_unlock(&br->multicast_lock); } +#if IS_ENABLED(CONFIG_IPV6) +static void br_ip6_multicast_query_expired(unsigned long data) +{ + struct net_bridge *br = (void *)data; + + spin_lock(&br->multicast_lock); + if (br->ip6_multicast_startup_queries_sent < + br->multicast_startup_query_count) + br->ip6_multicast_startup_queries_sent++; + + br_ip6_multicast_send_query(br, NULL, + br->ip6_multicast_startup_queries_sent); + + spin_unlock(&br->multicast_lock); +} +#endif + void br_multicast_init(struct net_bridge *br) { br->hash_elasticity = 4; @@ -1654,25 +1792,52 @@ void br_multicast_init(struct net_bridge *br) br->multicast_querier_interval = 255 * HZ; br->multicast_membership_interval = 260 * HZ; - br->multicast_querier_delay_time = 0; + br->ip4_multicast_querier_delay_time = 0; + br->ip6_multicast_querier_delay_time = 0; spin_lock_init(&br->multicast_lock); setup_timer(&br->multicast_router_timer, br_multicast_local_router_expired, 0); - setup_timer(&br->multicast_querier_timer, - br_multicast_querier_expired, (unsigned long)br); - setup_timer(&br->multicast_query_timer, br_multicast_query_expired, - (unsigned long)br); + setup_timer(&br->ip4_multicast_querier_timer, + br_ip4_multicast_querier_expired, (unsigned long)br); + setup_timer(&br->ip4_multicast_query_timer, + br_ip4_multicast_query_expired, (unsigned long)br); +#if IS_ENABLED(CONFIG_IPV6) + setup_timer(&br->ip6_multicast_querier_timer, + br_ip6_multicast_querier_expired, (unsigned long)br); + setup_timer(&br->ip6_multicast_query_timer, + br_ip6_multicast_query_expired, (unsigned long)br); +#endif } -void br_multicast_open(struct net_bridge *br) +static void br_ip4_multicast_open(struct net_bridge *br) { - br->multicast_startup_queries_sent = 0; + br->ip4_multicast_startup_queries_sent = 0; if (br->multicast_disabled) return; - mod_timer(&br->multicast_query_timer, jiffies); + mod_timer(&br->ip4_multicast_query_timer, jiffies); +} + +#if IS_ENABLED(CONFIG_IPV6) +static void br_ip6_multicast_open(struct net_bridge *br) +{ + br->ip6_multicast_startup_queries_sent = 0; + + if (br->multicast_disabled) + return; + + mod_timer(&br->ip6_multicast_query_timer, jiffies); +} +#endif + +void br_multicast_open(struct net_bridge *br) +{ + br_ip4_multicast_open(br); +#if IS_ENABLED(CONFIG_IPV6) + br_ip6_multicast_open(br); +#endif } void br_multicast_stop(struct net_bridge *br) @@ -1684,8 +1849,10 @@ void br_multicast_stop(struct net_bridge *br) int i; del_timer_sync(&br->multicast_router_timer); - del_timer_sync(&br->multicast_querier_timer); - del_timer_sync(&br->multicast_query_timer); + del_timer_sync(&br->ip4_multicast_querier_timer); + del_timer_sync(&br->ip6_multicast_querier_timer); + del_timer_sync(&br->ip4_multicast_query_timer); + del_timer_sync(&br->ip6_multicast_query_timer); spin_lock_bh(&br->multicast_lock); mdb = mlock_dereference(br->mdb, br); @@ -1788,21 +1955,38 @@ unlock: return err; } -static void br_multicast_start_querier(struct net_bridge *br) +static void br_ip4_multicast_start_querier(struct net_bridge *br) { struct net_bridge_port *port; - br_multicast_open(br); + br_ip4_multicast_open(br); list_for_each_entry(port, &br->port_list, list) { if (port->state == BR_STATE_DISABLED || port->state == BR_STATE_BLOCKING) continue; - __br_multicast_enable_port(port); + __br_ip4_multicast_enable_port(port); } } +#if IS_ENABLED(CONFIG_IPV6) +static void br_ip6_multicast_start_querier(struct net_bridge *br) +{ + struct net_bridge_port *port; + + br_ip6_multicast_open(br); + + list_for_each_entry(port, &br->port_list, list) { + if (port->state == BR_STATE_DISABLED || + port->state == BR_STATE_BLOCKING) + continue; + + __br_ip6_multicast_enable_port(port); + } +} +#endif + int br_multicast_toggle(struct net_bridge *br, unsigned long val) { int err = 0; @@ -1834,7 +2018,10 @@ rollback: goto rollback; } - br_multicast_start_querier(br); + br_ip4_multicast_start_querier(br); +#if IS_ENABLED(CONFIG_IPV6) + br_ip6_multicast_start_querier(br); +#endif unlock: spin_unlock_bh(&br->multicast_lock); @@ -1857,10 +2044,15 @@ int br_multicast_set_querier(struct net_bridge *br, unsigned long val) goto unlock; max_delay = br->multicast_query_response_interval; - if (!timer_pending(&br->multicast_querier_timer)) - br->multicast_querier_delay_time = jiffies + max_delay; + if (!timer_pending(&br->ip4_multicast_querier_timer)) + br->ip4_multicast_querier_delay_time = jiffies + max_delay; + if (!timer_pending(&br->ip6_multicast_querier_timer)) + br->ip6_multicast_querier_delay_time = jiffies + max_delay; - br_multicast_start_querier(br); + br_ip4_multicast_start_querier(br); +#if IS_ENABLED(CONFIG_IPV6) + br_ip6_multicast_start_querier(br); +#endif unlock: spin_unlock_bh(&br->multicast_lock); diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 2f7da41..10b4231 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -162,10 +162,12 @@ struct net_bridge_port #define BR_FLOOD 0x00000040 #ifdef CONFIG_BRIDGE_IGMP_SNOOPING - u32 multicast_startup_queries_sent; + u32 ip4_multicast_startup_queries_sent; + u32 ip6_multicast_startup_queries_sent; unsigned char multicast_router; struct timer_list multicast_router_timer; - struct timer_list multicast_query_timer; + struct timer_list ip4_multicast_query_timer; + struct timer_list ip6_multicast_query_timer; struct hlist_head mglist; struct hlist_node rlist; #endif @@ -258,7 +260,8 @@ struct net_bridge u32 hash_max; u32 multicast_last_member_count; - u32 multicast_startup_queries_sent; + u32 ip4_multicast_startup_queries_sent; + u32 ip6_multicast_startup_queries_sent; u32 multicast_startup_query_count; unsigned long multicast_last_member_interval; @@ -267,15 +270,18 @@ struct net_bridge unsigned long multicast_query_interval; unsigned long multicast_query_response_interval; unsigned long multicast_startup_query_interval; - unsigned long multicast_querier_delay_time; + unsigned long ip4_multicast_querier_delay_time; + unsigned long ip6_multicast_querier_delay_time; spinlock_t multicast_lock; struct net_bridge_mdb_htable __rcu *mdb; struct hlist_head router_list; struct timer_list multicast_router_timer; - struct timer_list multicast_querier_timer; - struct timer_list multicast_query_timer; + struct timer_list ip4_multicast_querier_timer; + struct timer_list ip6_multicast_querier_timer; + struct timer_list ip4_multicast_query_timer; + struct timer_list ip6_multicast_query_timer; #endif struct timer_list hello_timer; @@ -503,11 +509,31 @@ static inline bool br_multicast_is_router(struct net_bridge *br) timer_pending(&br->multicast_router_timer)); } -static inline bool br_multicast_querier_exists(struct net_bridge *br) +static inline bool br_ip4_multicast_querier_exists(struct net_bridge *br) { - return time_is_before_jiffies(br->multicast_querier_delay_time) && + return time_is_before_jiffies(br->ip4_multicast_querier_delay_time) && (br->multicast_querier || - timer_pending(&br->multicast_querier_timer)); + timer_pending(&br->ip4_multicast_querier_timer)); +} + +static inline bool br_ip6_multicast_querier_exists(struct net_bridge *br) +{ + return time_is_before_jiffies(br->ip6_multicast_querier_delay_time) && + (br->multicast_querier || + timer_pending(&br->ip6_multicast_querier_timer)); +} + +static inline bool br_multicast_querier_exists(struct net_bridge *br, + struct ethhdr *eth) +{ + switch (eth->h_proto) { + case (htons(ETH_P_IP)): + return br_ip4_multicast_querier_exists(br); + case (htons(ETH_P_IPV6)): + return br_ip6_multicast_querier_exists(br); + default: + return false; + } } #else static inline int br_multicast_rcv(struct net_bridge *br, @@ -565,7 +591,8 @@ static inline bool br_multicast_is_router(struct net_bridge *br) { return 0; } -static inline bool br_multicast_querier_exists(struct net_bridge *br) +static inline bool br_multicast_querier_exists(struct net_bridge *br, + struct ethhdr *eth) { return false; } -- 1.7.10.4 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/