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;
--
2.15.1.620.gb9897f4670-goog