From patchwork Tue Mar 29 08:40:53 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Timo Teras X-Patchwork-Id: 88736 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id EAA4BB6F01 for ; Tue, 29 Mar 2011 19:41:24 +1100 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751798Ab1C2IlK (ORCPT ); Tue, 29 Mar 2011 04:41:10 -0400 Received: from mail-ew0-f46.google.com ([209.85.215.46]:59172 "EHLO mail-ew0-f46.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751669Ab1C2IlH (ORCPT ); Tue, 29 Mar 2011 04:41:07 -0400 Received: by ewy4 with SMTP id 4so1419954ewy.19 for ; Tue, 29 Mar 2011 01:41:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:sender:from:to:cc:subject:date:message-id :x-mailer:in-reply-to:references:mime-version:content-type :content-transfer-encoding; bh=uTefmkee1uLTGmHGo8PJkEPOb3asMhzpWZav4TUl05s=; b=vVfuPpy34FG3HGUs5S+qNQNfrL5X7AaeDX7E8f+6oqDSbepOckADx2XJeoMohqwXed x5DYLPwsxPhdaUpf2fbWqv1d1L2YelG4z8ddWkImbRQIg/DggH3X3dpupgGjMr1jl9EB sIc0tL/aRY8TWKGJ3mpObMLgqau+Ocvg2l1UM= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=sender:from:to:cc:subject:date:message-id:x-mailer:in-reply-to :references:mime-version:content-type:content-transfer-encoding; b=KSzLpgiZN7cAXRtN4fJNnzTSQ061DGZ/jO5CAWD2aIpl2c3rpyBmEVwfuLR4n0W2KS shbjFWFHneuCKxI72J8882fSU31B9WtFO6vMblBZZOHwSbnzVtRjyS8t3b9QklhafIx3 lMDpKAs4K6kRbd6NAXtSb+cvScyYDja08dvZc= Received: by 10.14.50.7 with SMTP id y7mr2383482eeb.83.1301388065729; Tue, 29 Mar 2011 01:41:05 -0700 (PDT) Received: from vostro.ism.fin.wtbts.net (mail.fi.jw.org [83.145.235.193]) by mx.google.com with ESMTPS id v60sm3361427eeh.2.2011.03.29.01.41.04 (version=SSLv3 cipher=OTHER); Tue, 29 Mar 2011 01:41:05 -0700 (PDT) From: =?UTF-8?q?Timo=20Ter=C3=A4s?= To: netdev@vger.kernel.org Cc: Doug Kehn , =?UTF-8?q?Timo=20Ter=C3=A4s?= Subject: [PATCH] net: gre: provide multicast mappings for ipv4 and ipv6 Date: Tue, 29 Mar 2011 11:40:53 +0300 Message-Id: <1301388053-6083-1-git-send-email-timo.teras@iki.fi> X-Mailer: git-send-email 1.7.1 In-Reply-To: <4D8F6313.60408@iki.fi> References: <4D8F6313.60408@iki.fi> MIME-Version: 1.0 Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org 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 Signed-off-by: Timo Teräs Acked-by: Doug Kehn --- Compile tested only. Doug tested IPv4 side with the earlier patch. 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 #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);