aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOctavian Purdila <opurdila@ixiacom.com>2010-01-06 23:37:01 -0500
committerDavid S. Miller <davem@davemloft.net>2010-01-06 23:37:01 -0500
commit7ad6848c7e81a603605fad3f3575841aab004eea (patch)
treec95cc3473a2c47d6dedbbe5bc1a298546fc4127f
parent58933c643f86651decc4818cf680f9ec3b0460d2 (diff)
ip: fix mc_loop checks for tunnels with multicast outer addresses
When we have L3 tunnels with different inner/outer families (i.e. IPV4/IPV6) which use a multicast address as the outer tunnel destination address, multicast packets will be loopbacked back to the sending socket even if IP*_MULTICAST_LOOP is set to disabled. The mc_loop flag is present in the family specific part of the socket (e.g. the IPv4 or IPv4 specific part). setsockopt sets the inner family mc_loop flag. When the packet is pushed through the L3 tunnel it will eventually be processed by the outer family which if different will check the flag in a different part of the socket then it was set. Signed-off-by: Octavian Purdila <opurdila@ixiacom.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/ip.h16
-rw-r--r--net/ipv4/ip_output.c2
-rw-r--r--net/ipv6/ip6_output.c3
3 files changed, 18 insertions, 3 deletions
diff --git a/include/net/ip.h b/include/net/ip.h
index 85108cfbb1ae..d9a0e74d8923 100644
--- a/include/net/ip.h
+++ b/include/net/ip.h
@@ -326,6 +326,22 @@ static __inline__ void inet_reset_saddr(struct sock *sk)
326 326
327#endif 327#endif
328 328
329static inline int sk_mc_loop(struct sock *sk)
330{
331 if (!sk)
332 return 1;
333 switch (sk->sk_family) {
334 case AF_INET:
335 return inet_sk(sk)->mc_loop;
336#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
337 case AF_INET6:
338 return inet6_sk(sk)->mc_loop;
339#endif
340 }
341 __WARN();
342 return 1;
343}
344
329extern int ip_call_ra_chain(struct sk_buff *skb); 345extern int ip_call_ra_chain(struct sk_buff *skb);
330 346
331/* 347/*
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index e34013a78ef4..3451799e3dbf 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -254,7 +254,7 @@ int ip_mc_output(struct sk_buff *skb)
254 */ 254 */
255 255
256 if (rt->rt_flags&RTCF_MULTICAST) { 256 if (rt->rt_flags&RTCF_MULTICAST) {
257 if ((!sk || inet_sk(sk)->mc_loop) 257 if (sk_mc_loop(sk)
258#ifdef CONFIG_IP_MROUTE 258#ifdef CONFIG_IP_MROUTE
259 /* Small optimization: do not loopback not local frames, 259 /* Small optimization: do not loopback not local frames,
260 which returned after forwarding; they will be dropped 260 which returned after forwarding; they will be dropped
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index cd48801a8d6f..eb6d09728633 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -121,10 +121,9 @@ static int ip6_output2(struct sk_buff *skb)
121 skb->dev = dev; 121 skb->dev = dev;
122 122
123 if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr)) { 123 if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr)) {
124 struct ipv6_pinfo* np = skb->sk ? inet6_sk(skb->sk) : NULL;
125 struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb)); 124 struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb));
126 125
127 if (!(dev->flags & IFF_LOOPBACK) && (!np || np->mc_loop) && 126 if (!(dev->flags & IFF_LOOPBACK) && sk_mc_loop(skb->sk) &&
128 ((mroute6_socket(dev_net(dev)) && 127 ((mroute6_socket(dev_net(dev)) &&
129 !(IP6CB(skb)->flags & IP6SKB_FORWARDED)) || 128 !(IP6CB(skb)->flags & IP6SKB_FORWARDED)) ||
130 ipv6_chk_mcast_addr(dev, &ipv6_hdr(skb)->daddr, 129 ipv6_chk_mcast_addr(dev, &ipv6_hdr(skb)->daddr,