Subject: Re: [PATCH] net: gre: provide multicast mappings for ipv4 and ipv6

From: Doug Kehn <[email-masked]>
Date: Tue, 29 Mar 2011 13:26:02 -0700 (PDT)

--- On Tue, 3/29/11, Timo Teräs <[email-masked]> wrote:

> From: Timo Teräs <[email-masked]>
> Subject: [PATCH] net: gre: provide multicast mappings for ipv4 and ipv6
> To: [email-masked]
> Cc: "Doug Kehn" <[email-masked]>, "Timo Teräs" <[email-masked]>
> Date: Tuesday, March 29, 2011, 4:40 AM
> My commit 6d55cb91a0020ac0 (gre: fix
> hard header destination
> address checking) broke multicast.
> 
> The reason is that ip_gre used to get ipgre_header() calls
> with
> zero destination if we have NOARP or multicast destination.
> Instead
> the actual target was decided at ipgre_tunnel_xmit() time
> based on
> per-protocol dissection.
> 
> Instead of allowing the "abuse" of ->header() calls with
> invalid
> destination, this creates multicast mappings for ip_gre.
> This also
> fixes "ip neigh show nud noarp" to display the proper
> multicast
> mappings used by the gre device.
> 
> Reported-by: Doug Kehn <[email-masked]>
> Signed-off-by: Timo Teräs <[email-masked]>

Acked-by: Doug Kehn <[email-masked]>

> ---
> Compile tested only. Doug tested IPv4 side with the earlier
> patch.

This patch set [still] works with IPv4.

> 
> The IPv6 side needs a review. I'm not sure if mapped IPv4
> multicast
> addresses are intrepreted as multicast addresses by ndisc
> code or
> if we could map real IPv6 multicast addresses to IPv4
> multicast
> addresses.
> 
>  include/net/if_inet6.h |   16
> ++++++++++++++++
>  include/net/ip.h       | 
>   8 ++++++++
>  net/ipv4/arp.c     
>    |    3 +++
>  net/ipv6/ndisc.c       | 
>   2 ++
>  4 files changed, 29 insertions(+), 0 deletions(-)
> 
> diff --git a/include/net/if_inet6.h
> b/include/net/if_inet6.h
> index 04977ee..fccc218 100644
> --- a/include/net/if_inet6.h
> +++ b/include/net/if_inet6.h
> @@ -286,5 +286,21 @@ static inline void
> ipv6_ib_mc_map(const struct in6_addr *addr,
>      buf[9]  = broadcast[9];
>      memcpy(buf + 10, addr->s6_addr + 6,
> 10);
>  }
> +
> +static inline int ipv6_ipgre_mc_map(const struct in6_addr
> *addr,
> +           
>         const unsigned char
> *broadcast, char *buf)
> +{
> +    if ((broadcast[0] | broadcast[1] |
> broadcast[2] | broadcast[3]) != 0) {
> +        memcpy(buf,
> broadcast, 4);
> +    } else {
> +        /* v4mapped? */
> +        if
> ((addr->s6_addr32[0] | addr->s6_addr32[1] |
> +         
>    (addr->s6_addr32[2] ^
> htonl(0x0000ffff))) != 0)
> +           
> return -EINVAL;
> +        memcpy(buf,
> &addr->s6_addr32[3], 4);
> +    }
> +    return 0;
> +}
> +
>  #endif
>  #endif
> diff --git a/include/net/ip.h b/include/net/ip.h
> index a4f6311..7c41658 100644
> --- a/include/net/ip.h
> +++ b/include/net/ip.h
> @@ -339,6 +339,14 @@ static inline void ip_ib_mc_map(__be32
> naddr, const unsigned char *broadcast, ch
>      buf[16] = addr & 0x0f;
>  }
>  
> +static inline void ip_ipgre_mc_map(__be32 naddr, const
> unsigned char *broadcast, char *buf)
> +{
> +    if ((broadcast[0] | broadcast[1] |
> broadcast[2] | broadcast[3]) != 0)
> +        memcpy(buf,
> broadcast, 4);
> +    else
> +        memcpy(buf,
> &naddr, sizeof(naddr));
> +}
> +
>  #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
>  #include <linux/ipv6.h>
>  #endif
> diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c
> index 090d273..1b74d3b 100644
> --- a/net/ipv4/arp.c
> +++ b/net/ipv4/arp.c
> @@ -215,6 +215,9 @@ int arp_mc_map(__be32 addr, u8 *haddr,
> struct net_device *dev, int dir)
>      case ARPHRD_INFINIBAND:
>          ip_ib_mc_map(addr,
> dev->broadcast, haddr);
>          return 0;
> +    case ARPHRD_IPGRE:
> +       
> ip_ipgre_mc_map(addr, dev->broadcast, haddr);
> +        return 0;
>      default:
>          if (dir) {
>             
> memcpy(haddr, dev->broadcast, dev->addr_len);
> diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
> index 0e49c9d..92f952d 100644
> --- a/net/ipv6/ndisc.c
> +++ b/net/ipv6/ndisc.c
> @@ -341,6 +341,8 @@ int ndisc_mc_map(struct in6_addr *addr,
> char *buf, struct net_device *dev, int d
>      case ARPHRD_INFINIBAND:
>          ipv6_ib_mc_map(addr,
> dev->broadcast, buf);
>          return 0;
> +    case ARPHRD_IPGRE:
> +        return
> ipv6_ipgre_mc_map(addr, dev->broadcast, buf);
>      default:
>          if (dir) {
>             
> memcpy(buf, dev->broadcast, dev->addr_len);
> -- 
> 1.7.1
> 
> --
> To unsubscribe from this list: send the line "unsubscribe
> netdev" in
> the body of a message to [email-masked]
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>