Skip to content

Commit 5fdcce2

Browse files
wdauchydavem330
authored andcommitted
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 <[email protected]> Reviewed-by: Nicolas Dichtel <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent b32cb6f commit 5fdcce2

File tree

1 file changed

+47
-21
lines changed

1 file changed

+47
-21
lines changed

net/ipv6/ip6_tunnel.c

Lines changed: 47 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ static struct net_device_stats *ip6_get_stats(struct net_device *dev)
121121

122122
/**
123123
* ip6_tnl_lookup - fetch tunnel matching the end-point addresses
124+
* @link: ifindex of underlying interface
124125
* @remote: the address of the tunnel exit-point
125126
* @local: the address of the tunnel entry-point
126127
*
@@ -134,37 +135,56 @@ static struct net_device_stats *ip6_get_stats(struct net_device *dev)
134135
for (t = rcu_dereference(start); t; t = rcu_dereference(t->next))
135136

136137
static struct ip6_tnl *
137-
ip6_tnl_lookup(struct net *net, const struct in6_addr *remote, const struct in6_addr *local)
138+
ip6_tnl_lookup(struct net *net, int link,
139+
const struct in6_addr *remote, const struct in6_addr *local)
138140
{
139141
unsigned int hash = HASH(remote, local);
140-
struct ip6_tnl *t;
142+
struct ip6_tnl *t, *cand = NULL;
141143
struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
142144
struct in6_addr any;
143145

144146
for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) {
145-
if (ipv6_addr_equal(local, &t->parms.laddr) &&
146-
ipv6_addr_equal(remote, &t->parms.raddr) &&
147-
(t->dev->flags & IFF_UP))
147+
if (!ipv6_addr_equal(local, &t->parms.laddr) ||
148+
!ipv6_addr_equal(remote, &t->parms.raddr) ||
149+
!(t->dev->flags & IFF_UP))
150+
continue;
151+
152+
if (link == t->parms.link)
148153
return t;
154+
else
155+
cand = t;
149156
}
150157

151158
memset(&any, 0, sizeof(any));
152159
hash = HASH(&any, local);
153160
for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) {
154-
if (ipv6_addr_equal(local, &t->parms.laddr) &&
155-
ipv6_addr_any(&t->parms.raddr) &&
156-
(t->dev->flags & IFF_UP))
161+
if (!ipv6_addr_equal(local, &t->parms.laddr) ||
162+
!ipv6_addr_any(&t->parms.raddr) ||
163+
!(t->dev->flags & IFF_UP))
164+
continue;
165+
166+
if (link == t->parms.link)
157167
return t;
168+
else if (!cand)
169+
cand = t;
158170
}
159171

160172
hash = HASH(remote, &any);
161173
for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) {
162-
if (ipv6_addr_equal(remote, &t->parms.raddr) &&
163-
ipv6_addr_any(&t->parms.laddr) &&
164-
(t->dev->flags & IFF_UP))
174+
if (!ipv6_addr_equal(remote, &t->parms.raddr) ||
175+
!ipv6_addr_any(&t->parms.laddr) ||
176+
!(t->dev->flags & IFF_UP))
177+
continue;
178+
179+
if (link == t->parms.link)
165180
return t;
181+
else if (!cand)
182+
cand = t;
166183
}
167184

185+
if (cand)
186+
return cand;
187+
168188
t = rcu_dereference(ip6n->collect_md_tun);
169189
if (t && t->dev->flags & IFF_UP)
170190
return t;
@@ -351,7 +371,8 @@ static struct ip6_tnl *ip6_tnl_locate(struct net *net,
351371
(t = rtnl_dereference(*tp)) != NULL;
352372
tp = &t->next) {
353373
if (ipv6_addr_equal(local, &t->parms.laddr) &&
354-
ipv6_addr_equal(remote, &t->parms.raddr)) {
374+
ipv6_addr_equal(remote, &t->parms.raddr) &&
375+
p->link == t->parms.link) {
355376
if (create)
356377
return ERR_PTR(-EEXIST);
357378

@@ -485,7 +506,7 @@ ip6_tnl_err(struct sk_buff *skb, __u8 ipproto, struct inet6_skb_parm *opt,
485506
processing of the error. */
486507

487508
rcu_read_lock();
488-
t = ip6_tnl_lookup(dev_net(skb->dev), &ipv6h->daddr, &ipv6h->saddr);
509+
t = ip6_tnl_lookup(dev_net(skb->dev), skb->dev->ifindex, &ipv6h->daddr, &ipv6h->saddr);
489510
if (!t)
490511
goto out;
491512

@@ -887,7 +908,7 @@ static int ipxip6_rcv(struct sk_buff *skb, u8 ipproto,
887908
int ret = -1;
888909

889910
rcu_read_lock();
890-
t = ip6_tnl_lookup(dev_net(skb->dev), &ipv6h->saddr, &ipv6h->daddr);
911+
t = ip6_tnl_lookup(dev_net(skb->dev), skb->dev->ifindex, &ipv6h->saddr, &ipv6h->daddr);
891912

892913
if (t) {
893914
u8 tproto = READ_ONCE(t->parms.proto);
@@ -1420,8 +1441,10 @@ ip6_tnl_start_xmit(struct sk_buff *skb, struct net_device *dev)
14201441
static void ip6_tnl_link_config(struct ip6_tnl *t)
14211442
{
14221443
struct net_device *dev = t->dev;
1444+
struct net_device *tdev = NULL;
14231445
struct __ip6_tnl_parm *p = &t->parms;
14241446
struct flowi6 *fl6 = &t->fl.u.ip6;
1447+
unsigned int mtu;
14251448
int t_hlen;
14261449

14271450
memcpy(dev->dev_addr, &p->laddr, sizeof(struct in6_addr));
@@ -1457,22 +1480,25 @@ static void ip6_tnl_link_config(struct ip6_tnl *t)
14571480
struct rt6_info *rt = rt6_lookup(t->net,
14581481
&p->raddr, &p->laddr,
14591482
p->link, NULL, strict);
1483+
if (rt) {
1484+
tdev = rt->dst.dev;
1485+
ip6_rt_put(rt);
1486+
}
14601487

1461-
if (!rt)
1462-
return;
1488+
if (!tdev && p->link)
1489+
tdev = __dev_get_by_index(t->net, p->link);
14631490

1464-
if (rt->dst.dev) {
1465-
dev->hard_header_len = rt->dst.dev->hard_header_len +
1466-
t_hlen;
1491+
if (tdev) {
1492+
dev->hard_header_len = tdev->hard_header_len + t_hlen;
1493+
mtu = min_t(unsigned int, tdev->mtu, IP6_MAX_MTU);
14671494

1468-
dev->mtu = rt->dst.dev->mtu - t_hlen;
1495+
dev->mtu = mtu - t_hlen;
14691496
if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT))
14701497
dev->mtu -= 8;
14711498

14721499
if (dev->mtu < IPV6_MIN_MTU)
14731500
dev->mtu = IPV6_MIN_MTU;
14741501
}
1475-
ip6_rt_put(rt);
14761502
}
14771503
}
14781504

0 commit comments

Comments
 (0)