Skip to content

Commit bbc318f

Browse files
committed
Merge branch 'bridge-mrd'
Linus Lüssing says: ==================== bridge: implement Multicast Router Discovery (RFC4286) This patchset adds initial Multicast Router Discovery support to the Linux bridge (RFC4286). With MRD it is possible to detect multicast routers and mark bridge ports and forward multicast packets to such routers accordingly. So far, multicast routers are detected via IGMP/MLD queries and PIM messages in the Linux bridge. As there is only one active, selected querier at a time RFC4541 ("Considerations for Internet Group Management Protocol (IGMP) and Multicast Listener Discovery (MLD) Snooping Switches") section 2.1.1.a) recommends snooping Multicast Router Advertisements as provided by MRD (RFC4286). The first two patches are refactoring some existing code which is reused for parsing the Multicast Router Advertisements later in the fourth patch. The third patch lets the bridge join the all-snoopers multicast address to be able to reliably receive the Multicast Router Advertisements. What is not implemented yet from RFC4286 yet: * Sending Multicast Router Solicitations: -> RFC4286: "[...] may be sent when [...] an interface is (re-)initialized [or] MRD is enabled" * Snooping Multicast Router Terminations: -> currently this only relies on our own timeouts * Adjusting timeouts with the values provided in the announcements Changes in v2: * rebased to current net-next/master (no conflicts/changes) ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
2 parents 6679cf0 + 4b3087c commit bbc318f

File tree

13 files changed

+275
-132
lines changed

13 files changed

+275
-132
lines changed

include/linux/igmp.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <linux/skbuff.h>
1919
#include <linux/timer.h>
2020
#include <linux/in.h>
21+
#include <linux/ip.h>
2122
#include <linux/refcount.h>
2223
#include <uapi/linux/igmp.h>
2324

@@ -106,6 +107,14 @@ struct ip_mc_list {
106107
#define IGMPV3_QQIC(value) IGMPV3_EXP(0x80, 4, 3, value)
107108
#define IGMPV3_MRC(value) IGMPV3_EXP(0x80, 4, 3, value)
108109

110+
static inline int ip_mc_may_pull(struct sk_buff *skb, unsigned int len)
111+
{
112+
if (skb_transport_offset(skb) + ip_transport_len(skb) < len)
113+
return -EINVAL;
114+
115+
return pskb_may_pull(skb, len);
116+
}
117+
109118
extern int ip_check_mc_rcu(struct in_device *dev, __be32 mc_addr, __be32 src_addr, u8 proto);
110119
extern int igmp_rcv(struct sk_buff *);
111120
extern int ip_mc_join_group(struct sock *sk, struct ip_mreqn *imr);
@@ -130,6 +139,6 @@ extern void ip_mc_unmap(struct in_device *);
130139
extern void ip_mc_remap(struct in_device *);
131140
extern void ip_mc_dec_group(struct in_device *in_dev, __be32 addr);
132141
extern void ip_mc_inc_group(struct in_device *in_dev, __be32 addr);
133-
int ip_mc_check_igmp(struct sk_buff *skb, struct sk_buff **skb_trimmed);
142+
int ip_mc_check_igmp(struct sk_buff *skb);
134143

135144
#endif

include/linux/in.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,11 @@ static inline bool ipv4_is_lbcast(__be32 addr)
6060
return addr == htonl(INADDR_BROADCAST);
6161
}
6262

63+
static inline bool ipv4_is_all_snoopers(__be32 addr)
64+
{
65+
return addr == htonl(INADDR_ALLSNOOPERS_GROUP);
66+
}
67+
6368
static inline bool ipv4_is_zeronet(__be32 addr)
6469
{
6570
return (addr & htonl(0xff000000)) == htonl(0x00000000);

include/linux/ip.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,9 @@ static inline struct iphdr *ipip_hdr(const struct sk_buff *skb)
3434
{
3535
return (struct iphdr *)skb_transport_header(skb);
3636
}
37+
38+
static inline unsigned int ip_transport_len(const struct sk_buff *skb)
39+
{
40+
return ntohs(ip_hdr(skb)->tot_len) - skb_network_header_len(skb);
41+
}
3742
#endif /* _LINUX_IP_H */

include/linux/ipv6.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,12 @@ static inline struct ipv6hdr *ipipv6_hdr(const struct sk_buff *skb)
104104
return (struct ipv6hdr *)skb_transport_header(skb);
105105
}
106106

107+
static inline unsigned int ipv6_transport_len(const struct sk_buff *skb)
108+
{
109+
return ntohs(ipv6_hdr(skb)->payload_len) + sizeof(struct ipv6hdr) -
110+
skb_network_header_len(skb);
111+
}
112+
107113
/*
108114
This structure contains results of exthdrs parsing
109115
as offsets from skb->nh.

include/net/addrconf.h

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ struct prefix_info {
4949
struct in6_addr prefix;
5050
};
5151

52+
#include <linux/ipv6.h>
5253
#include <linux/netdevice.h>
5354
#include <net/if_inet6.h>
5455
#include <net/ipv6.h>
@@ -201,6 +202,15 @@ u32 ipv6_addr_label(struct net *net, const struct in6_addr *addr,
201202
/*
202203
* multicast prototypes (mcast.c)
203204
*/
205+
static inline int ipv6_mc_may_pull(struct sk_buff *skb,
206+
unsigned int len)
207+
{
208+
if (skb_transport_offset(skb) + ipv6_transport_len(skb) < len)
209+
return -EINVAL;
210+
211+
return pskb_may_pull(skb, len);
212+
}
213+
204214
int ipv6_sock_mc_join(struct sock *sk, int ifindex,
205215
const struct in6_addr *addr);
206216
int ipv6_sock_mc_drop(struct sock *sk, int ifindex,
@@ -219,7 +229,8 @@ void ipv6_mc_unmap(struct inet6_dev *idev);
219229
void ipv6_mc_remap(struct inet6_dev *idev);
220230
void ipv6_mc_init_dev(struct inet6_dev *idev);
221231
void ipv6_mc_destroy_dev(struct inet6_dev *idev);
222-
int ipv6_mc_check_mld(struct sk_buff *skb, struct sk_buff **skb_trimmed);
232+
int ipv6_mc_check_icmpv6(struct sk_buff *skb);
233+
int ipv6_mc_check_mld(struct sk_buff *skb);
223234
void addrconf_dad_failure(struct sk_buff *skb, struct inet6_ifaddr *ifp);
224235

225236
bool ipv6_chk_mcast_addr(struct net_device *dev, const struct in6_addr *group,
@@ -489,6 +500,20 @@ static inline bool ipv6_addr_is_solict_mult(const struct in6_addr *addr)
489500
#endif
490501
}
491502

503+
static inline bool ipv6_addr_is_all_snoopers(const struct in6_addr *addr)
504+
{
505+
#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64
506+
__be64 *p = (__be64 *)addr;
507+
508+
return ((p[0] ^ cpu_to_be64(0xff02000000000000UL)) |
509+
(p[1] ^ cpu_to_be64(0x6a))) == 0UL;
510+
#else
511+
return ((addr->s6_addr32[0] ^ htonl(0xff020000)) |
512+
addr->s6_addr32[1] | addr->s6_addr32[2] |
513+
(addr->s6_addr32[3] ^ htonl(0x0000006a))) == 0;
514+
#endif
515+
}
516+
492517
#ifdef CONFIG_PROC_FS
493518
int if6_proc_init(void);
494519
void if6_proc_exit(void);

include/uapi/linux/icmpv6.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,8 @@ struct icmp6hdr {
108108
#define ICMPV6_MOBILE_PREFIX_SOL 146
109109
#define ICMPV6_MOBILE_PREFIX_ADV 147
110110

111+
#define ICMPV6_MRDISC_ADV 151
112+
111113
/*
112114
* Codes for Destination Unreachable
113115
*/

include/uapi/linux/igmp.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ struct igmpv3_query {
9393
#define IGMP_MTRACE_RESP 0x1e
9494
#define IGMP_MTRACE 0x1f
9595

96+
#define IGMP_MRDISC_ADV 0x30 /* From RFC4286 */
9697

9798
/*
9899
* Use the BSD names for these for compatibility

include/uapi/linux/in.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -292,10 +292,11 @@ struct sockaddr_in {
292292
#define IN_LOOPBACK(a) ((((long int) (a)) & 0xff000000) == 0x7f000000)
293293

294294
/* Defines for Multicast INADDR */
295-
#define INADDR_UNSPEC_GROUP 0xe0000000U /* 224.0.0.0 */
296-
#define INADDR_ALLHOSTS_GROUP 0xe0000001U /* 224.0.0.1 */
297-
#define INADDR_ALLRTRS_GROUP 0xe0000002U /* 224.0.0.2 */
298-
#define INADDR_MAX_LOCAL_GROUP 0xe00000ffU /* 224.0.0.255 */
295+
#define INADDR_UNSPEC_GROUP 0xe0000000U /* 224.0.0.0 */
296+
#define INADDR_ALLHOSTS_GROUP 0xe0000001U /* 224.0.0.1 */
297+
#define INADDR_ALLRTRS_GROUP 0xe0000002U /* 224.0.0.2 */
298+
#define INADDR_ALLSNOOPERS_GROUP 0xe000006aU /* 224.0.0.106 */
299+
#define INADDR_MAX_LOCAL_GROUP 0xe00000ffU /* 224.0.0.255 */
299300
#endif
300301

301302
/* <asm/byteorder.h> contains the htonl type stuff.. */

net/batman-adv/multicast.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -674,7 +674,7 @@ static void batadv_mcast_mla_update(struct work_struct *work)
674674
*/
675675
static bool batadv_mcast_is_report_ipv4(struct sk_buff *skb)
676676
{
677-
if (ip_mc_check_igmp(skb, NULL) < 0)
677+
if (ip_mc_check_igmp(skb) < 0)
678678
return false;
679679

680680
switch (igmp_hdr(skb)->type) {
@@ -741,7 +741,7 @@ static int batadv_mcast_forw_mode_check_ipv4(struct batadv_priv *bat_priv,
741741
*/
742742
static bool batadv_mcast_is_report_ipv6(struct sk_buff *skb)
743743
{
744-
if (ipv6_mc_check_mld(skb, NULL) < 0)
744+
if (ipv6_mc_check_mld(skb) < 0)
745745
return false;
746746

747747
switch (icmp6_hdr(skb)->icmp6_type) {

0 commit comments

Comments
 (0)