[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20171220170607.41516-7-lorenzo@google.com>
Date: Thu, 21 Dec 2017 02:06:06 +0900
From: Lorenzo Colitti <lorenzo@...gle.com>
To: netdev@...r.kernel.org
Cc: steffen.klassert@...unet.com, subashab@...eaurora.org,
nharold@...gle.com, davem@...emloft.net,
Lorenzo Colitti <lorenzo@...gle.com>
Subject: [PATCH ipsec-next 6/7] net: xfrm: Allow userspace to configure keyed VTI tunnels.
This commit allows userspace to configure keyed VTI tunnels by
adding a IFLA_VTI_FLAGS attribute and a VTI_KEYED flag. When set,
the flag causes the tunnel parameter i_flags to be set to
TUNNEL_KEY.
Creating both a non-keyed VTI and a keyed VTI on the same IP
src+dst pair is not useful. Because non-keyed VTIs always accept
packets, in such a configuration the keyed VTI would not receive
any traffic. This is disallowed by modifying the ip_tunnel_find
and vti6_locate functions to treat VTIs on the same src+dst pair
as identical unless they are both keyed (in which case they can
coexist, by design). So attempts to create such duplicate tunnels
- or to change one tunnel in such a way that it would duplicate
another - will fail with EEXIST.
Signed-off-by: Lorenzo Colitti <lorenzo@...gle.com>
---
include/uapi/linux/if_tunnel.h | 4 ++++
net/ipv4/ip_tunnel.c | 10 +++++++++-
net/ipv4/ip_vti.c | 26 +++++++++++++++++++++++---
net/ipv6/ip6_vti.c | 33 +++++++++++++++++++++++++++++++--
4 files changed, 67 insertions(+), 6 deletions(-)
diff --git a/include/uapi/linux/if_tunnel.h b/include/uapi/linux/if_tunnel.h
index 1b3d148c45..b431b1c209 100644
--- a/include/uapi/linux/if_tunnel.h
+++ b/include/uapi/linux/if_tunnel.h
@@ -148,6 +148,9 @@ enum {
/* VTI-mode i_flags */
#define VTI_ISVTI ((__force __be16)0x0001)
+/* VTI netlink iflags. */
+#define VTI_KEYED 0x0001
+
enum {
IFLA_VTI_UNSPEC,
IFLA_VTI_LINK,
@@ -156,6 +159,7 @@ enum {
IFLA_VTI_LOCAL,
IFLA_VTI_REMOTE,
IFLA_VTI_FWMARK,
+ IFLA_VTI_FLAGS,
__IFLA_VTI_MAX,
};
diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c
index f45968bb81..9a0a56b491 100644
--- a/net/ipv4/ip_tunnel.c
+++ b/net/ipv4/ip_tunnel.c
@@ -84,6 +84,14 @@ static bool ip_tunnel_key_match(const struct ip_tunnel_parm *p,
return !(flags & TUNNEL_KEY);
}
+static bool ip_tunnel_match(const struct ip_tunnel_parm *p,
+ __be32 flags, u8 lookup_flags, __be32 key)
+{
+ return ip_tunnel_key_match(p, flags, lookup_flags, key) ||
+ ((p->i_flags & flags & VTI_ISVTI) &&
+ !(p->i_flags & flags & TUNNEL_KEY));
+}
+
/* Fallback tunnel: no source, no destination, no key, no options
Tunnel hash table:
@@ -242,7 +250,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, 0, key))
+ ip_tunnel_match(&t->parms, flags, 0, key))
break;
}
return t;
diff --git a/net/ipv4/ip_vti.c b/net/ipv4/ip_vti.c
index 9d28433a60..1f52719228 100644
--- a/net/ipv4/ip_vti.c
+++ b/net/ipv4/ip_vti.c
@@ -385,6 +385,16 @@ static int vti4_err(struct sk_buff *skb, u32 info)
return tunnel ? 0 : -1;
}
+static __be16 vti_flags_to_tnl_flags(__u16 flags)
+{
+ return VTI_ISVTI | ((flags & VTI_KEYED) ? TUNNEL_KEY : 0);
+}
+
+static __u16 tnl_flags_to_vti_flags(__be16 i_flags)
+{
+ return (i_flags & TUNNEL_KEY) ? VTI_KEYED : 0;
+}
+
static int
vti_tunnel_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
@@ -525,6 +535,8 @@ static void vti_netlink_parms(struct nlattr *data[],
struct ip_tunnel_parm *parms,
__u32 *fwmark)
{
+ __u16 flags = 0;
+
memset(parms, 0, sizeof(*parms));
parms->iph.protocol = IPPROTO_IPIP;
@@ -532,8 +544,6 @@ static void vti_netlink_parms(struct nlattr *data[],
if (!data)
return;
- parms->i_flags = VTI_ISVTI;
-
if (data[IFLA_VTI_LINK])
parms->link = nla_get_u32(data[IFLA_VTI_LINK]);
@@ -551,6 +561,11 @@ static void vti_netlink_parms(struct nlattr *data[],
if (data[IFLA_VTI_FWMARK])
*fwmark = nla_get_u32(data[IFLA_VTI_FWMARK]);
+
+ if (data[IFLA_VTI_FLAGS])
+ flags = nla_get_u16(data[IFLA_VTI_FLAGS]);
+
+ parms->i_flags = vti_flags_to_tnl_flags(flags);
}
static int vti_newlink(struct net *src_net, struct net_device *dev,
@@ -591,6 +606,8 @@ static size_t vti_get_size(const struct net_device *dev)
nla_total_size(4) +
/* IFLA_VTI_FWMARK */
nla_total_size(4) +
+ /* IFLA_VTI_FLAGS */
+ nla_total_size(2) +
0;
}
@@ -604,7 +621,9 @@ static int vti_fill_info(struct sk_buff *skb, const struct net_device *dev)
nla_put_be32(skb, IFLA_VTI_OKEY, p->o_key) ||
nla_put_in_addr(skb, IFLA_VTI_LOCAL, p->iph.saddr) ||
nla_put_in_addr(skb, IFLA_VTI_REMOTE, p->iph.daddr) ||
- nla_put_u32(skb, IFLA_VTI_FWMARK, t->fwmark))
+ nla_put_u32(skb, IFLA_VTI_FWMARK, t->fwmark) ||
+ nla_put_u16(skb, IFLA_VTI_FLAGS,
+ tnl_flags_to_vti_flags(p->i_flags)))
return -EMSGSIZE;
return 0;
@@ -617,6 +636,7 @@ static const struct nla_policy vti_policy[IFLA_VTI_MAX + 1] = {
[IFLA_VTI_LOCAL] = { .len = FIELD_SIZEOF(struct iphdr, saddr) },
[IFLA_VTI_REMOTE] = { .len = FIELD_SIZEOF(struct iphdr, daddr) },
[IFLA_VTI_FWMARK] = { .type = NLA_U32 },
+ [IFLA_VTI_FLAGS] = { .type = NLA_U16 },
};
static struct rtnl_link_ops vti_link_ops __read_mostly = {
diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c
index bf64821b8a..18c2695dc3 100644
--- a/net/ipv6/ip6_vti.c
+++ b/net/ipv6/ip6_vti.c
@@ -86,6 +86,13 @@ static bool vti6_match_key(const struct ip6_tnl *t, __be32 key, bool in)
return !(flags & TUNNEL_KEY) || tunnel_key == key;
}
+static bool vti6_match_tunnel(const struct ip6_tnl *t, struct __ip6_tnl_parm *p)
+{
+ return !(t->parms.i_flags & TUNNEL_KEY) ||
+ !(p->i_flags & TUNNEL_KEY) ||
+ vti6_match_key(t, p->i_key, true);
+}
+
/**
* vti6_tnl_lookup - fetch tunnel matching the end-point addresses and key
* @net: network namespace
@@ -280,7 +287,7 @@ static struct ip6_tnl *vti6_locate(struct net *net, struct __ip6_tnl_parm *p,
tp = &t->next) {
if (ipv6_addr_equal(local, &t->parms.laddr) &&
ipv6_addr_equal(remote, &t->parms.raddr) &&
- vti6_match_key(t, p->i_key, true)) {
+ vti6_match_tunnel(t, p)) {
if (create)
return NULL;
@@ -990,9 +997,21 @@ static int vti6_validate(struct nlattr *tb[], struct nlattr *data[],
return 0;
}
+static __be16 vti_flags_to_tnl_flags(__u16 i_flags)
+{
+ return VTI_ISVTI | ((i_flags & VTI_KEYED) ? TUNNEL_KEY : 0);
+}
+
+static __u16 tnl_flags_to_vti_flags(__be16 i_flags)
+{
+ return (i_flags & TUNNEL_KEY) ? VTI_KEYED : 0;
+}
+
static void vti6_netlink_parms(struct nlattr *data[],
struct __ip6_tnl_parm *parms)
{
+ __u16 flags = 0;
+
memset(parms, 0, sizeof(*parms));
if (!data)
@@ -1015,6 +1034,11 @@ static void vti6_netlink_parms(struct nlattr *data[],
if (data[IFLA_VTI_FWMARK])
parms->fwmark = nla_get_u32(data[IFLA_VTI_FWMARK]);
+
+ if (data[IFLA_VTI_FLAGS])
+ flags = nla_get_u16(data[IFLA_VTI_FLAGS]);
+
+ parms->i_flags = vti_flags_to_tnl_flags(flags);
}
static int vti6_newlink(struct net *src_net, struct net_device *dev,
@@ -1084,6 +1108,8 @@ static size_t vti6_get_size(const struct net_device *dev)
nla_total_size(4) +
/* IFLA_VTI_FWMARK */
nla_total_size(4) +
+ /* IFLA_VTI_FLAGS */
+ nla_total_size(2) +
0;
}
@@ -1097,7 +1123,9 @@ static int vti6_fill_info(struct sk_buff *skb, const struct net_device *dev)
nla_put_in6_addr(skb, IFLA_VTI_REMOTE, &parm->raddr) ||
nla_put_be32(skb, IFLA_VTI_IKEY, parm->i_key) ||
nla_put_be32(skb, IFLA_VTI_OKEY, parm->o_key) ||
- nla_put_u32(skb, IFLA_VTI_FWMARK, parm->fwmark))
+ nla_put_u32(skb, IFLA_VTI_FWMARK, parm->fwmark) ||
+ nla_put_u16(skb, IFLA_VTI_FLAGS,
+ tnl_flags_to_vti_flags(parm->i_flags)))
goto nla_put_failure;
return 0;
@@ -1112,6 +1140,7 @@ static const struct nla_policy vti6_policy[IFLA_VTI_MAX + 1] = {
[IFLA_VTI_IKEY] = { .type = NLA_U32 },
[IFLA_VTI_OKEY] = { .type = NLA_U32 },
[IFLA_VTI_FWMARK] = { .type = NLA_U32 },
+ [IFLA_VTI_FLAGS] = { .type = NLA_U16 },
};
static struct rtnl_link_ops vti6_link_ops __read_mostly = {
--
2.15.1.620.gb9897f4670-goog
Powered by blists - more mailing lists