mirror of https://gitee.com/openkylin/linux.git
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: William Dauchy <w.dauchy@criteo.com> Reviewed-by: Nicolas Dichtel <nicolas.dichtel@6wind.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
b32cb6fcf1
commit
5fdcce211b
|
@ -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)
|
||||||
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,
|
||||||
(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,
|
||||||
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,
|
||||||
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)
|
||||||
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)
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue