Commit 5fdcce21 authored by William Dauchy's avatar William Dauchy Committed by David S. Miller

net, ip6_tunnel: enhance tunnel locate with link check

With ipip, it is possible to create an extra interface explicitly
attached to a given physical interface:

  # ip link show tunl0
  4: tunl0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ipip 0.0.0.0 brd 0.0.0.0
  # ip link add tunl1 type ipip dev eth0
  # ip link show tunl1
  6: tunl1@eth0: <NOARP> mtu 1480 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ipip 0.0.0.0 brd 0.0.0.0

But it is not possible with ip6tnl:

  # ip link show ip6tnl0
  5: ip6tnl0@NONE: <NOARP> mtu 1452 qdisc noop state DOWN mode DEFAULT group default qlen 1000
      link/tunnel6 :: brd ::
  # ip link add ip6tnl1 type ip6tnl dev eth0
  RTNETLINK answers: File exists

This patch aims to make it possible by adding link comparaison in both
tunnel locate and lookup functions; we also modify mtu calculation when
attached to an interface with a lower mtu.

This permits to make use of x-netns communication by moving the newly
created tunnel in a given netns.
Signed-off-by: default avatarWilliam Dauchy <w.dauchy@criteo.com>
Reviewed-by: default avatarNicolas Dichtel <nicolas.dichtel@6wind.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent b32cb6fc
...@@ -121,6 +121,7 @@ static struct net_device_stats *ip6_get_stats(struct net_device *dev) ...@@ -121,6 +121,7 @@ static struct net_device_stats *ip6_get_stats(struct net_device *dev)
/** /**
* ip6_tnl_lookup - fetch tunnel matching the end-point addresses * ip6_tnl_lookup - fetch tunnel matching the end-point addresses
* @link: ifindex of underlying interface
* @remote: the address of the tunnel exit-point * @remote: the address of the tunnel exit-point
* @local: the address of the tunnel entry-point * @local: the address of the tunnel entry-point
* *
...@@ -134,37 +135,56 @@ static struct net_device_stats *ip6_get_stats(struct net_device *dev) ...@@ -134,37 +135,56 @@ static struct net_device_stats *ip6_get_stats(struct net_device *dev)
for (t = rcu_dereference(start); t; t = rcu_dereference(t->next)) for (t = rcu_dereference(start); t; t = rcu_dereference(t->next))
static struct ip6_tnl * static struct ip6_tnl *
ip6_tnl_lookup(struct net *net, const struct in6_addr *remote, const struct in6_addr *local) ip6_tnl_lookup(struct net *net, int link,
const struct in6_addr *remote, const struct in6_addr *local)
{ {
unsigned int hash = HASH(remote, local); unsigned int hash = HASH(remote, local);
struct ip6_tnl *t; struct ip6_tnl *t, *cand = NULL;
struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
struct in6_addr any; struct in6_addr any;
for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) { for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) {
if (ipv6_addr_equal(local, &t->parms.laddr) && if (!ipv6_addr_equal(local, &t->parms.laddr) ||
ipv6_addr_equal(remote, &t->parms.raddr) && !ipv6_addr_equal(remote, &t->parms.raddr) ||
(t->dev->flags & IFF_UP)) !(t->dev->flags & IFF_UP))
continue;
if (link == t->parms.link)
return t; return t;
else
cand = t;
} }
memset(&any, 0, sizeof(any)); memset(&any, 0, sizeof(any));
hash = HASH(&any, local); hash = HASH(&any, local);
for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) { for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) {
if (ipv6_addr_equal(local, &t->parms.laddr) && if (!ipv6_addr_equal(local, &t->parms.laddr) ||
ipv6_addr_any(&t->parms.raddr) && !ipv6_addr_any(&t->parms.raddr) ||
(t->dev->flags & IFF_UP)) !(t->dev->flags & IFF_UP))
continue;
if (link == t->parms.link)
return t; return t;
else if (!cand)
cand = t;
} }
hash = HASH(remote, &any); hash = HASH(remote, &any);
for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) { for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) {
if (ipv6_addr_equal(remote, &t->parms.raddr) && if (!ipv6_addr_equal(remote, &t->parms.raddr) ||
ipv6_addr_any(&t->parms.laddr) && !ipv6_addr_any(&t->parms.laddr) ||
(t->dev->flags & IFF_UP)) !(t->dev->flags & IFF_UP))
continue;
if (link == t->parms.link)
return t; return t;
else if (!cand)
cand = t;
} }
if (cand)
return cand;
t = rcu_dereference(ip6n->collect_md_tun); t = rcu_dereference(ip6n->collect_md_tun);
if (t && t->dev->flags & IFF_UP) if (t && t->dev->flags & IFF_UP)
return t; return t;
...@@ -351,7 +371,8 @@ static struct ip6_tnl *ip6_tnl_locate(struct net *net, ...@@ -351,7 +371,8 @@ static struct ip6_tnl *ip6_tnl_locate(struct net *net,
(t = rtnl_dereference(*tp)) != NULL; (t = rtnl_dereference(*tp)) != NULL;
tp = &t->next) { tp = &t->next) {
if (ipv6_addr_equal(local, &t->parms.laddr) && if (ipv6_addr_equal(local, &t->parms.laddr) &&
ipv6_addr_equal(remote, &t->parms.raddr)) { ipv6_addr_equal(remote, &t->parms.raddr) &&
p->link == t->parms.link) {
if (create) if (create)
return ERR_PTR(-EEXIST); return ERR_PTR(-EEXIST);
...@@ -485,7 +506,7 @@ ip6_tnl_err(struct sk_buff *skb, __u8 ipproto, struct inet6_skb_parm *opt, ...@@ -485,7 +506,7 @@ ip6_tnl_err(struct sk_buff *skb, __u8 ipproto, struct inet6_skb_parm *opt,
processing of the error. */ processing of the error. */
rcu_read_lock(); rcu_read_lock();
t = ip6_tnl_lookup(dev_net(skb->dev), &ipv6h->daddr, &ipv6h->saddr); t = ip6_tnl_lookup(dev_net(skb->dev), skb->dev->ifindex, &ipv6h->daddr, &ipv6h->saddr);
if (!t) if (!t)
goto out; goto out;
...@@ -887,7 +908,7 @@ static int ipxip6_rcv(struct sk_buff *skb, u8 ipproto, ...@@ -887,7 +908,7 @@ static int ipxip6_rcv(struct sk_buff *skb, u8 ipproto,
int ret = -1; int ret = -1;
rcu_read_lock(); rcu_read_lock();
t = ip6_tnl_lookup(dev_net(skb->dev), &ipv6h->saddr, &ipv6h->daddr); t = ip6_tnl_lookup(dev_net(skb->dev), skb->dev->ifindex, &ipv6h->saddr, &ipv6h->daddr);
if (t) { if (t) {
u8 tproto = READ_ONCE(t->parms.proto); u8 tproto = READ_ONCE(t->parms.proto);
...@@ -1420,8 +1441,10 @@ ip6_tnl_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -1420,8 +1441,10 @@ ip6_tnl_start_xmit(struct sk_buff *skb, struct net_device *dev)
static void ip6_tnl_link_config(struct ip6_tnl *t) static void ip6_tnl_link_config(struct ip6_tnl *t)
{ {
struct net_device *dev = t->dev; struct net_device *dev = t->dev;
struct net_device *tdev = NULL;
struct __ip6_tnl_parm *p = &t->parms; struct __ip6_tnl_parm *p = &t->parms;
struct flowi6 *fl6 = &t->fl.u.ip6; struct flowi6 *fl6 = &t->fl.u.ip6;
unsigned int mtu;
int t_hlen; int t_hlen;
memcpy(dev->dev_addr, &p->laddr, sizeof(struct in6_addr)); memcpy(dev->dev_addr, &p->laddr, sizeof(struct in6_addr));
...@@ -1457,22 +1480,25 @@ static void ip6_tnl_link_config(struct ip6_tnl *t) ...@@ -1457,22 +1480,25 @@ static void ip6_tnl_link_config(struct ip6_tnl *t)
struct rt6_info *rt = rt6_lookup(t->net, struct rt6_info *rt = rt6_lookup(t->net,
&p->raddr, &p->laddr, &p->raddr, &p->laddr,
p->link, NULL, strict); p->link, NULL, strict);
if (rt) {
tdev = rt->dst.dev;
ip6_rt_put(rt);
}
if (!rt) if (!tdev && p->link)
return; tdev = __dev_get_by_index(t->net, p->link);
if (rt->dst.dev) { if (tdev) {
dev->hard_header_len = rt->dst.dev->hard_header_len + dev->hard_header_len = tdev->hard_header_len + t_hlen;
t_hlen; mtu = min_t(unsigned int, tdev->mtu, IP6_MAX_MTU);
dev->mtu = rt->dst.dev->mtu - t_hlen; dev->mtu = mtu - t_hlen;
if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT)) if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT))
dev->mtu -= 8; dev->mtu -= 8;
if (dev->mtu < IPV6_MIN_MTU) if (dev->mtu < IPV6_MIN_MTU)
dev->mtu = IPV6_MIN_MTU; dev->mtu = IPV6_MIN_MTU;
} }
ip6_rt_put(rt);
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment