Skip to content

Commit bd2a979

Browse files
T-Xsimonwunderlich
authored andcommitted
batman-adv: Always flood IGMP/MLD reports
With this patch IGMP or MLD reports are always flooded. This is necessary for the upcoming bridge integration to function without multicast packet loss. With the report handling so far bridges might miss interested multicast listeners, leading to wrongly excluding ports from multicast packet forwarding. Currently we are treating IGMP/MLD reports, the messages bridges use to learn about interested multicast listeners, just as any other multicast packet: We try to send them to nodes matching its multicast destination. Unfortunately, the destination address of reports of the older IGMPv2/MLDv1 protocol families do not strictly adhere to their own protocol: More precisely, the interested receiver, an IGMPv2 or MLDv1 querier, itself usually does not listen to the multicast destination address of any reports. Therefore with this patch we are simply excluding IGMP/MLD reports from the multicast forwarding code path and keep flooding them. By that any bridge receives them and can properly learn about listeners. To avoid compatibility issues with older nodes not yet implementing this report handling, we need to force them to flood reports: We do this by bumping the multicast TVLV version to 2, effectively disabling their multicast optimization. Tested-by: Simon Wunderlich <[email protected]> Signed-off-by: Linus Lüssing <[email protected]> Signed-off-by: Marek Lindner <[email protected]> Signed-off-by: Sven Eckelmann <[email protected]> Signed-off-by: Simon Wunderlich <[email protected]>
1 parent c0f25c8 commit bd2a979

File tree

2 files changed

+75
-14
lines changed

2 files changed

+75
-14
lines changed

net/batman-adv/Kconfig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ config BATMAN_ADV_NC
6666

6767
config BATMAN_ADV_MCAST
6868
bool "Multicast optimisation"
69-
depends on BATMAN_ADV
69+
depends on BATMAN_ADV && INET
7070
default n
7171
help
7272
This option enables the multicast optimisation which aims to

net/batman-adv/multicast.c

Lines changed: 74 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,11 @@
2525
#include <linux/errno.h>
2626
#include <linux/etherdevice.h>
2727
#include <linux/fs.h>
28+
#include <linux/icmpv6.h>
2829
#include <linux/if_ether.h>
29-
#include <linux/in6.h>
30+
#include <linux/igmp.h>
3031
#include <linux/in.h>
32+
#include <linux/in6.h>
3133
#include <linux/ip.h>
3234
#include <linux/ipv6.h>
3335
#include <linux/kref.h>
@@ -236,7 +238,7 @@ static bool batadv_mcast_mla_tvlv_update(struct batadv_priv *bat_priv)
236238
if (batadv_mcast_has_bridge(bat_priv)) {
237239
if (bat_priv->mcast.enabled) {
238240
batadv_tvlv_container_unregister(bat_priv,
239-
BATADV_TVLV_MCAST, 1);
241+
BATADV_TVLV_MCAST, 2);
240242
bat_priv->mcast.enabled = false;
241243
}
242244

@@ -245,7 +247,7 @@ static bool batadv_mcast_mla_tvlv_update(struct batadv_priv *bat_priv)
245247

246248
if (!bat_priv->mcast.enabled ||
247249
mcast_data.flags != bat_priv->mcast.flags) {
248-
batadv_tvlv_container_register(bat_priv, BATADV_TVLV_MCAST, 1,
250+
batadv_tvlv_container_register(bat_priv, BATADV_TVLV_MCAST, 2,
249251
&mcast_data, sizeof(mcast_data));
250252
bat_priv->mcast.flags = mcast_data.flags;
251253
bat_priv->mcast.enabled = true;
@@ -282,6 +284,31 @@ void batadv_mcast_mla_update(struct batadv_priv *bat_priv)
282284
batadv_mcast_mla_list_free(bat_priv, &mcast_list);
283285
}
284286

287+
/**
288+
* batadv_mcast_is_report_ipv4 - check for IGMP reports
289+
* @skb: the ethernet frame destined for the mesh
290+
*
291+
* This call might reallocate skb data.
292+
*
293+
* Checks whether the given frame is a valid IGMP report.
294+
*
295+
* Return: If so then true, otherwise false.
296+
*/
297+
static bool batadv_mcast_is_report_ipv4(struct sk_buff *skb)
298+
{
299+
if (ip_mc_check_igmp(skb, NULL) < 0)
300+
return false;
301+
302+
switch (igmp_hdr(skb)->type) {
303+
case IGMP_HOST_MEMBERSHIP_REPORT:
304+
case IGMPV2_HOST_MEMBERSHIP_REPORT:
305+
case IGMPV3_HOST_MEMBERSHIP_REPORT:
306+
return true;
307+
}
308+
309+
return false;
310+
}
311+
285312
/**
286313
* batadv_mcast_forw_mode_check_ipv4 - check for optimized forwarding potential
287314
* @bat_priv: the bat priv with all the soft interface information
@@ -304,6 +331,9 @@ static int batadv_mcast_forw_mode_check_ipv4(struct batadv_priv *bat_priv,
304331
if (!pskb_may_pull(skb, sizeof(struct ethhdr) + sizeof(*iphdr)))
305332
return -ENOMEM;
306333

334+
if (batadv_mcast_is_report_ipv4(skb))
335+
return -EINVAL;
336+
307337
iphdr = ip_hdr(skb);
308338

309339
/* TODO: Implement Multicast Router Discovery (RFC4286),
@@ -320,6 +350,31 @@ static int batadv_mcast_forw_mode_check_ipv4(struct batadv_priv *bat_priv,
320350
return 0;
321351
}
322352

353+
#if IS_ENABLED(CONFIG_IPV6)
354+
/**
355+
* batadv_mcast_is_report_ipv6 - check for MLD reports
356+
* @skb: the ethernet frame destined for the mesh
357+
*
358+
* This call might reallocate skb data.
359+
*
360+
* Checks whether the given frame is a valid MLD report.
361+
*
362+
* Return: If so then true, otherwise false.
363+
*/
364+
static bool batadv_mcast_is_report_ipv6(struct sk_buff *skb)
365+
{
366+
if (ipv6_mc_check_mld(skb, NULL) < 0)
367+
return false;
368+
369+
switch (icmp6_hdr(skb)->icmp6_type) {
370+
case ICMPV6_MGM_REPORT:
371+
case ICMPV6_MLD2_REPORT:
372+
return true;
373+
}
374+
375+
return false;
376+
}
377+
323378
/**
324379
* batadv_mcast_forw_mode_check_ipv6 - check for optimized forwarding potential
325380
* @bat_priv: the bat priv with all the soft interface information
@@ -341,6 +396,9 @@ static int batadv_mcast_forw_mode_check_ipv6(struct batadv_priv *bat_priv,
341396
if (!pskb_may_pull(skb, sizeof(struct ethhdr) + sizeof(*ip6hdr)))
342397
return -ENOMEM;
343398

399+
if (batadv_mcast_is_report_ipv6(skb))
400+
return -EINVAL;
401+
344402
ip6hdr = ipv6_hdr(skb);
345403

346404
/* TODO: Implement Multicast Router Discovery (RFC4286),
@@ -357,6 +415,7 @@ static int batadv_mcast_forw_mode_check_ipv6(struct batadv_priv *bat_priv,
357415

358416
return 0;
359417
}
418+
#endif
360419

361420
/**
362421
* batadv_mcast_forw_mode_check - check for optimized forwarding potential
@@ -385,9 +444,11 @@ static int batadv_mcast_forw_mode_check(struct batadv_priv *bat_priv,
385444
case ETH_P_IP:
386445
return batadv_mcast_forw_mode_check_ipv4(bat_priv, skb,
387446
is_unsnoopable);
447+
#if IS_ENABLED(CONFIG_IPV6)
388448
case ETH_P_IPV6:
389449
return batadv_mcast_forw_mode_check_ipv6(bat_priv, skb,
390450
is_unsnoopable);
451+
#endif
391452
default:
392453
return -EINVAL;
393454
}
@@ -728,18 +789,18 @@ static void batadv_mcast_want_ipv6_update(struct batadv_priv *bat_priv,
728789
}
729790

730791
/**
731-
* batadv_mcast_tvlv_ogm_handler_v1 - process incoming multicast tvlv container
792+
* batadv_mcast_tvlv_ogm_handler - process incoming multicast tvlv container
732793
* @bat_priv: the bat priv with all the soft interface information
733794
* @orig: the orig_node of the ogm
734795
* @flags: flags indicating the tvlv state (see batadv_tvlv_handler_flags)
735796
* @tvlv_value: tvlv buffer containing the multicast data
736797
* @tvlv_value_len: tvlv buffer length
737798
*/
738-
static void batadv_mcast_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv,
739-
struct batadv_orig_node *orig,
740-
u8 flags,
741-
void *tvlv_value,
742-
u16 tvlv_value_len)
799+
static void batadv_mcast_tvlv_ogm_handler(struct batadv_priv *bat_priv,
800+
struct batadv_orig_node *orig,
801+
u8 flags,
802+
void *tvlv_value,
803+
u16 tvlv_value_len)
743804
{
744805
bool orig_mcast_enabled = !(flags & BATADV_TVLV_HANDLER_OGM_CIFNOTFND);
745806
u8 mcast_flags = BATADV_NO_FLAGS;
@@ -789,8 +850,8 @@ static void batadv_mcast_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv,
789850
*/
790851
void batadv_mcast_init(struct batadv_priv *bat_priv)
791852
{
792-
batadv_tvlv_handler_register(bat_priv, batadv_mcast_tvlv_ogm_handler_v1,
793-
NULL, BATADV_TVLV_MCAST, 1,
853+
batadv_tvlv_handler_register(bat_priv, batadv_mcast_tvlv_ogm_handler,
854+
NULL, BATADV_TVLV_MCAST, 2,
794855
BATADV_TVLV_HANDLER_OGM_CIFNOTFND);
795856
}
796857

@@ -800,8 +861,8 @@ void batadv_mcast_init(struct batadv_priv *bat_priv)
800861
*/
801862
void batadv_mcast_free(struct batadv_priv *bat_priv)
802863
{
803-
batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_MCAST, 1);
804-
batadv_tvlv_handler_unregister(bat_priv, BATADV_TVLV_MCAST, 1);
864+
batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_MCAST, 2);
865+
batadv_tvlv_handler_unregister(bat_priv, BATADV_TVLV_MCAST, 2);
805866

806867
spin_lock_bh(&bat_priv->tt.commit_lock);
807868
batadv_mcast_mla_tt_retract(bat_priv, NULL);

0 commit comments

Comments
 (0)