Skip to content

Commit b00589a

Browse files
T-Xdavem330
authored andcommitted
bridge: disable snooping if there is no querier
If there is no querier on a link then we won't get periodic reports and therefore won't be able to learn about multicast listeners behind ports, potentially leading to lost multicast packets, especially for multicast listeners that joined before the creation of the bridge. These lost multicast packets can appear since c5c2326 ("bridge: Add multicast_querier toggle and disable queries by default") in particular. With this patch we are flooding multicast packets if our querier is disabled and if we didn't detect any other querier. A grace period of the Maximum Response Delay of the querier is added to give multicast responses enough time to arrive and to be learned from before disabling the flooding behaviour again. Signed-off-by: Linus Lüssing <linus.luessing@web.de> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent cf3c4c0 commit b00589a

File tree

4 files changed

+46
-11
lines changed

4 files changed

+46
-11
lines changed

net/bridge/br_device.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,8 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
7070
}
7171

7272
mdst = br_mdb_get(br, skb, vid);
73-
if (mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb))
73+
if ((mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) &&
74+
br_multicast_querier_exists(br))
7475
br_multicast_deliver(mdst, skb);
7576
else
7677
br_flood_deliver(br, skb, false);

net/bridge/br_input.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,8 @@ int br_handle_frame_finish(struct sk_buff *skb)
101101
unicast = false;
102102
} else if (is_multicast_ether_addr(dest)) {
103103
mdst = br_mdb_get(br, skb, vid);
104-
if (mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) {
104+
if ((mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) &&
105+
br_multicast_querier_exists(br)) {
105106
if ((mdst && mdst->mglist) ||
106107
br_multicast_is_router(br))
107108
skb2 = skb;

net/bridge/br_multicast.c

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1014,6 +1014,16 @@ static int br_ip6_multicast_mld2_report(struct net_bridge *br,
10141014
}
10151015
#endif
10161016

1017+
static void br_multicast_update_querier_timer(struct net_bridge *br,
1018+
unsigned long max_delay)
1019+
{
1020+
if (!timer_pending(&br->multicast_querier_timer))
1021+
br->multicast_querier_delay_time = jiffies + max_delay;
1022+
1023+
mod_timer(&br->multicast_querier_timer,
1024+
jiffies + br->multicast_querier_interval);
1025+
}
1026+
10171027
/*
10181028
* Add port to router_list
10191029
* list is maintained ordered by pointer value
@@ -1064,11 +1074,11 @@ static void br_multicast_mark_router(struct net_bridge *br,
10641074

10651075
static void br_multicast_query_received(struct net_bridge *br,
10661076
struct net_bridge_port *port,
1067-
int saddr)
1077+
int saddr,
1078+
unsigned long max_delay)
10681079
{
10691080
if (saddr)
1070-
mod_timer(&br->multicast_querier_timer,
1071-
jiffies + br->multicast_querier_interval);
1081+
br_multicast_update_querier_timer(br, max_delay);
10721082
else if (timer_pending(&br->multicast_querier_timer))
10731083
return;
10741084

@@ -1096,8 +1106,6 @@ static int br_ip4_multicast_query(struct net_bridge *br,
10961106
(port && port->state == BR_STATE_DISABLED))
10971107
goto out;
10981108

1099-
br_multicast_query_received(br, port, !!iph->saddr);
1100-
11011109
group = ih->group;
11021110

11031111
if (skb->len == sizeof(*ih)) {
@@ -1121,6 +1129,8 @@ static int br_ip4_multicast_query(struct net_bridge *br,
11211129
IGMPV3_MRC(ih3->code) * (HZ / IGMP_TIMER_SCALE) : 1;
11221130
}
11231131

1132+
br_multicast_query_received(br, port, !!iph->saddr, max_delay);
1133+
11241134
if (!group)
11251135
goto out;
11261136

@@ -1176,8 +1186,6 @@ static int br_ip6_multicast_query(struct net_bridge *br,
11761186
(port && port->state == BR_STATE_DISABLED))
11771187
goto out;
11781188

1179-
br_multicast_query_received(br, port, !ipv6_addr_any(&ip6h->saddr));
1180-
11811189
if (skb->len == sizeof(*mld)) {
11821190
if (!pskb_may_pull(skb, sizeof(*mld))) {
11831191
err = -EINVAL;
@@ -1198,6 +1206,9 @@ static int br_ip6_multicast_query(struct net_bridge *br,
11981206
max_delay = mld2q->mld2q_mrc ? MLDV2_MRC(ntohs(mld2q->mld2q_mrc)) : 1;
11991207
}
12001208

1209+
br_multicast_query_received(br, port, !ipv6_addr_any(&ip6h->saddr),
1210+
max_delay);
1211+
12011212
if (!group)
12021213
goto out;
12031214

@@ -1643,6 +1654,8 @@ void br_multicast_init(struct net_bridge *br)
16431654
br->multicast_querier_interval = 255 * HZ;
16441655
br->multicast_membership_interval = 260 * HZ;
16451656

1657+
br->multicast_querier_delay_time = 0;
1658+
16461659
spin_lock_init(&br->multicast_lock);
16471660
setup_timer(&br->multicast_router_timer,
16481661
br_multicast_local_router_expired, 0);
@@ -1831,15 +1844,23 @@ int br_multicast_toggle(struct net_bridge *br, unsigned long val)
18311844

18321845
int br_multicast_set_querier(struct net_bridge *br, unsigned long val)
18331846
{
1847+
unsigned long max_delay;
1848+
18341849
val = !!val;
18351850

18361851
spin_lock_bh(&br->multicast_lock);
18371852
if (br->multicast_querier == val)
18381853
goto unlock;
18391854

18401855
br->multicast_querier = val;
1841-
if (val)
1842-
br_multicast_start_querier(br);
1856+
if (!val)
1857+
goto unlock;
1858+
1859+
max_delay = br->multicast_query_response_interval;
1860+
if (!timer_pending(&br->multicast_querier_timer))
1861+
br->multicast_querier_delay_time = jiffies + max_delay;
1862+
1863+
br_multicast_start_querier(br);
18431864

18441865
unlock:
18451866
spin_unlock_bh(&br->multicast_lock);

net/bridge/br_private.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,7 @@ struct net_bridge
267267
unsigned long multicast_query_interval;
268268
unsigned long multicast_query_response_interval;
269269
unsigned long multicast_startup_query_interval;
270+
unsigned long multicast_querier_delay_time;
270271

271272
spinlock_t multicast_lock;
272273
struct net_bridge_mdb_htable __rcu *mdb;
@@ -501,6 +502,13 @@ static inline bool br_multicast_is_router(struct net_bridge *br)
501502
(br->multicast_router == 1 &&
502503
timer_pending(&br->multicast_router_timer));
503504
}
505+
506+
static inline bool br_multicast_querier_exists(struct net_bridge *br)
507+
{
508+
return time_is_before_jiffies(br->multicast_querier_delay_time) &&
509+
(br->multicast_querier ||
510+
timer_pending(&br->multicast_querier_timer));
511+
}
504512
#else
505513
static inline int br_multicast_rcv(struct net_bridge *br,
506514
struct net_bridge_port *port,
@@ -557,6 +565,10 @@ static inline bool br_multicast_is_router(struct net_bridge *br)
557565
{
558566
return 0;
559567
}
568+
static inline bool br_multicast_querier_exists(struct net_bridge *br)
569+
{
570+
return false;
571+
}
560572
static inline void br_mdb_init(void)
561573
{
562574
}

0 commit comments

Comments
 (0)