[PATCH ipsec-next 6/7] net: xfrm: Allow userspace to configure keyed VTI tunnels.
flat view
STALE3215d
From: Lorenzo Colitti <hidden>
Date: 2017-12-20 17:06:40
Subsystem:
networking drivers, networking [general], networking [ipsec], networking [ipv4/ipv6], the rest · Maintainers:
Andrew Lunn, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Steffen Klassert, Herbert Xu, David Ahern, Ido Schimmel, Linus Torvalds
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 <redacted> --- 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