From patchwork Wed Dec 20 17:06:02 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lorenzo Colitti X-Patchwork-Id: 851558 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=google.com header.i=@google.com header.b="h8U7v7bD"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3z21R534BGz9s83 for ; Thu, 21 Dec 2017 04:07:13 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755615AbdLTRGh (ORCPT ); Wed, 20 Dec 2017 12:06:37 -0500 Received: from mail-pg0-f68.google.com ([74.125.83.68]:37573 "EHLO mail-pg0-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753452AbdLTRGa (ORCPT ); Wed, 20 Dec 2017 12:06:30 -0500 Received: by mail-pg0-f68.google.com with SMTP id o13so1410447pgp.4 for ; Wed, 20 Dec 2017 09:06:30 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=E9/kNJjVaBws9ibGb8hCsNgLrtLjyDytdiO//N0da6E=; b=h8U7v7bDFSRQlb0uPbVVQzQ1sKMeYlfJw0+08zJkZPITJkugQHLSBCNy93pMU2Q/6i xiG38MQ2IxwDfOkToR8xSY37YIJ1gbV78mfq9OSzKR6vvjbBLVKOnJFyTL+MZ1hkxXgg hiP52hrNBats6bepa5WrbLe2iJ2Y6oaajFBP0LGJYYBD5Jh6y+y7BLNNmNNUILWdBD9v WYjbTb5uad0edzeEIRaWV91jQtJz66Eao4dDpxLgOBrrRq3UVcxT5UuKtCD1ZpEZ4MVy GoLAGRaCaXNaD1iZ50JfxEStYsmquF2osXmgEjjChze0CGaeHveT9TuN9KQbtxW0wGdT 2ftg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=E9/kNJjVaBws9ibGb8hCsNgLrtLjyDytdiO//N0da6E=; b=Lu2caMWZuB31AybKXZHTRMW+bMBZF1vEHLBuU4x/UOK1Y+w8yxXJF3T9+5nD25LFmZ AiQLvQeNFxOHMLLpPBpubzU4i3c+UUFJYZ3RqFDEaFDAJLRgNPbfGHUOtqrne89udffR uJhaTyM+41ekt+Gd9BhMA4BtYGxfnTqNPIKhLy53wXW1aulVGm4dOFnrfuub1m3dj1ON 4DwZ/AOHsM1wNykuRuVr5r5yQcbx5q/hFxj44CInr1+R5bNCbrRB8k+pAbTXXjQP/bRk NKvEkkrFE9wUZAtXVmYes9iG35f1xkOhWI5/ZxMHq7iSjQttUXAoe/Aief0uDWqBPNxR zVHg== X-Gm-Message-State: AKGB3mI4fEM+Zs1XzplSRtHfUET7/KhTHgqmUmZrBs1dp44K+angv6Ff +rDTUKQXpC0+Bt7oE/mbWdOl2lYQVjw= X-Google-Smtp-Source: ACJfBouJUOOOV8MRZaB/hWt5ErUskOLMs2z3+/6AzactL9BzLxX0XFUmGrZ0AVoUGNBvjFKAhAjD0A== X-Received: by 10.99.124.16 with SMTP id x16mr7035756pgc.124.1513789589356; Wed, 20 Dec 2017 09:06:29 -0800 (PST) Received: from lorenzo.tok.corp.google.com ([100.103.3.232]) by smtp.gmail.com with ESMTPSA id t62sm29103067pgt.23.2017.12.20.09.06.27 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 20 Dec 2017 09:06:28 -0800 (PST) From: Lorenzo Colitti To: netdev@vger.kernel.org Cc: steffen.klassert@secunet.com, subashab@codeaurora.org, nharold@google.com, davem@davemloft.net, Lorenzo Colitti Subject: [PATCH ipsec-next 2/7] net: ipv4: Add new flags to tunnel lookup. Date: Thu, 21 Dec 2017 02:06:02 +0900 Message-Id: <20171220170607.41516-3-lorenzo@google.com> X-Mailer: git-send-email 2.15.1.620.gb9897f4670-goog In-Reply-To: <20171220170607.41516-1-lorenzo@google.com> References: <20171220170607.41516-1-lorenzo@google.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org This patch adds support for two new flags to ip_tunnel_lookup. - TUNNEL_LOOKUP_NO_KEY: ignores the tunnel's i_key when determining which hash bucket to look up the tunnel in. This is useful for tunnels such as VTI, which have i_keys, but are always hashed into bucket 0. - TUNNEL_LOOKUP_OKEY: finds the tunnel by o_key instead of i_key. Together, these flags allow processing ICMP errors correctly on keyed tunnels where i_key != o_key. If such tunnels receive an ICMP error, the only information available in the packet is the o_key, so we must be able to find a tunnel by o_key alone. For that to work, the tunnel hash must not depend on the i_key, because if it does, we won't be able to find it by o_key alone. TUNNEL_LOOKUP_NO_KEY is very similar to TUNNEL_NO_KEY so it might be possible just to use TUNNEL_NO_KEY instead. However, it might be confusing to see code simultaneously pass in both TUNNEL_NO_KEY and TUNNEL_KEY. These flags are numbered separately from tunnel flags because they are not tunnel properties but properties of tunnel lookups. (Also, the tunnel flags are 16 bits and all but one is unused.) The flags are passed into ip_lookup by adding a new parameter. This could also be done by expanding the existing flags parameter from __be16 to __be32 and ensuring that the new flags are all above the 16-bit boundary. Signed-off-by: Lorenzo Colitti --- include/net/ip_tunnels.h | 6 +++++- net/ipv4/ip_gre.c | 6 +++--- net/ipv4/ip_tunnel.c | 22 +++++++++++++--------- net/ipv4/ip_vti.c | 4 ++-- net/ipv4/ipip.c | 6 +++--- 5 files changed, 26 insertions(+), 18 deletions(-) diff --git a/include/net/ip_tunnels.h b/include/net/ip_tunnels.h index 1f16773cfd..19d97b993a 100644 --- a/include/net/ip_tunnels.h +++ b/include/net/ip_tunnels.h @@ -163,6 +163,10 @@ struct ip_tunnel { #define TUNNEL_OPTIONS_PRESENT \ (TUNNEL_GENEVE_OPT | TUNNEL_VXLAN_OPT | TUNNEL_ERSPAN_OPT) +/* Flags for ip_tunnel_lookup. */ +#define TUNNEL_LOOKUP_NO_KEY 0x01 +#define TUNNEL_LOOKUP_OKEY 0x02 + struct tnl_ptk_info { __be16 flags; __be16 proto; @@ -276,7 +280,7 @@ int ip_tunnel_change_mtu(struct net_device *dev, int new_mtu); void ip_tunnel_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *tot); struct ip_tunnel *ip_tunnel_lookup(struct ip_tunnel_net *itn, - int link, __be16 flags, + int link, __be16 flags, u8 lookup_flags, __be32 remote, __be32 local, __be32 key); diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index fd4d6e96da..f16a46cb19 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -182,7 +182,7 @@ static void ipgre_err(struct sk_buff *skb, u32 info, itn = net_generic(net, ipgre_net_id); iph = (const struct iphdr *)(icmp_hdr(skb) + 1); - t = ip_tunnel_lookup(itn, skb->dev->ifindex, tpi->flags, + t = ip_tunnel_lookup(itn, skb->dev->ifindex, tpi->flags, 0, iph->daddr, iph->saddr, tpi->key); if (!t) @@ -280,7 +280,7 @@ static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi, */ tpi->key = cpu_to_be32(ntohs(ershdr->session_id) & ID_MASK); tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, - tpi->flags | TUNNEL_KEY, + tpi->flags | TUNNEL_KEY, 0, iph->saddr, iph->daddr, tpi->key); if (tunnel) { @@ -356,7 +356,7 @@ static int __ipgre_rcv(struct sk_buff *skb, const struct tnl_ptk_info *tpi, struct ip_tunnel *tunnel; iph = ip_hdr(skb); - tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, tpi->flags, + tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, tpi->flags, 0, iph->saddr, iph->daddr, tpi->key); if (tunnel) { diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c index 539c8f22c4..f45968bb81 100644 --- a/net/ipv4/ip_tunnel.c +++ b/net/ipv4/ip_tunnel.c @@ -70,11 +70,13 @@ static unsigned int ip_tunnel_hash(__be32 key, __be32 remote) } static bool ip_tunnel_key_match(const struct ip_tunnel_parm *p, - __be16 flags, __be32 key) + __be32 flags, u8 lookup_flags, __be32 key) { + __be32 tunnel_key = (lookup_flags & TUNNEL_LOOKUP_OKEY) ? p->o_key : + p->i_key; if (p->i_flags & TUNNEL_KEY) { if (flags & TUNNEL_KEY) - return key == p->i_key; + return key == tunnel_key; else /* key expected, none present */ return false; @@ -94,15 +96,17 @@ static bool ip_tunnel_key_match(const struct ip_tunnel_parm *p, Given src, dst and key, find appropriate for input tunnel. */ struct ip_tunnel *ip_tunnel_lookup(struct ip_tunnel_net *itn, - int link, __be16 flags, + int link, __be16 flags, u8 lookup_flags, __be32 remote, __be32 local, __be32 key) { unsigned int hash; struct ip_tunnel *t, *cand = NULL; struct hlist_head *head; + __be32 hash_key; - hash = ip_tunnel_hash(key, remote); + hash_key = (lookup_flags & TUNNEL_LOOKUP_NO_KEY) ? 0 : key; + hash = ip_tunnel_hash(hash_key, remote); head = &itn->tunnels[hash]; hlist_for_each_entry_rcu(t, head, hash_node) { @@ -111,7 +115,7 @@ struct ip_tunnel *ip_tunnel_lookup(struct ip_tunnel_net *itn, !(t->dev->flags & IFF_UP)) continue; - if (!ip_tunnel_key_match(&t->parms, flags, key)) + if (!ip_tunnel_key_match(&t->parms, flags, lookup_flags, key)) continue; if (t->parms.link == link) @@ -126,7 +130,7 @@ struct ip_tunnel *ip_tunnel_lookup(struct ip_tunnel_net *itn, !(t->dev->flags & IFF_UP)) continue; - if (!ip_tunnel_key_match(&t->parms, flags, key)) + if (!ip_tunnel_key_match(&t->parms, flags, lookup_flags, key)) continue; if (t->parms.link == link) @@ -135,7 +139,7 @@ struct ip_tunnel *ip_tunnel_lookup(struct ip_tunnel_net *itn, cand = t; } - hash = ip_tunnel_hash(key, 0); + hash = ip_tunnel_hash(hash_key, 0); head = &itn->tunnels[hash]; hlist_for_each_entry_rcu(t, head, hash_node) { @@ -146,7 +150,7 @@ struct ip_tunnel *ip_tunnel_lookup(struct ip_tunnel_net *itn, if (!(t->dev->flags & IFF_UP)) continue; - if (!ip_tunnel_key_match(&t->parms, flags, key)) + if (!ip_tunnel_key_match(&t->parms, flags, lookup_flags, key)) continue; if (t->parms.link == link) @@ -238,7 +242,7 @@ static struct ip_tunnel *ip_tunnel_find(struct ip_tunnel_net *itn, remote == t->parms.iph.daddr && link == t->parms.link && type == t->dev->type && - ip_tunnel_key_match(&t->parms, flags, key)) + ip_tunnel_key_match(&t->parms, flags, 0, key)) break; } return t; diff --git a/net/ipv4/ip_vti.c b/net/ipv4/ip_vti.c index 949f432a5f..804cee8126 100644 --- a/net/ipv4/ip_vti.c +++ b/net/ipv4/ip_vti.c @@ -57,7 +57,7 @@ static int vti_input(struct sk_buff *skb, int nexthdr, __be32 spi, struct net *net = dev_net(skb->dev); struct ip_tunnel_net *itn = net_generic(net, vti_net_id); - tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY, + tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY, 0, iph->saddr, iph->daddr, 0); if (tunnel) { if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) @@ -278,7 +278,7 @@ static int vti4_err(struct sk_buff *skb, u32 info) int protocol = iph->protocol; struct ip_tunnel_net *itn = net_generic(net, vti_net_id); - tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY, + tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY, 0, iph->daddr, iph->saddr, 0); if (!tunnel) return -1; diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index c891235b49..81f94ffb92 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -167,7 +167,7 @@ static int ipip_err(struct sk_buff *skb, u32 info) goto out; } - t = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY, + t = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY, 0, iph->daddr, iph->saddr, 0); if (!t) { err = -ENOENT; @@ -224,8 +224,8 @@ static int ipip_tunnel_rcv(struct sk_buff *skb, u8 ipproto) const struct iphdr *iph; iph = ip_hdr(skb); - tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY, - iph->saddr, iph->daddr, 0); + tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY, 0, + iph->saddr, iph->daddr, 0); if (tunnel) { const struct tnl_ptk_info *tpi;