Blame view

net/ipv4/ip_tunnel.c 29 KB
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
  /*
   * Copyright (c) 2013 Nicira, Inc.
   *
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of version 2 of the GNU General Public
   * License as published by the Free Software Foundation.
   *
   * This program is distributed in the hope that it will be useful, but
   * WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
   * General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
   * 02110-1301, USA
   */
  
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  
  #include <linux/capability.h>
  #include <linux/module.h>
  #include <linux/types.h>
  #include <linux/kernel.h>
  #include <linux/slab.h>
  #include <linux/uaccess.h>
  #include <linux/skbuff.h>
  #include <linux/netdevice.h>
  #include <linux/in.h>
  #include <linux/tcp.h>
  #include <linux/udp.h>
  #include <linux/if_arp.h>
c54419321   Pravin B Shelar   GRE: Refactor GRE...
33
34
35
36
37
38
39
40
41
  #include <linux/init.h>
  #include <linux/in6.h>
  #include <linux/inetdevice.h>
  #include <linux/igmp.h>
  #include <linux/netfilter_ipv4.h>
  #include <linux/etherdevice.h>
  #include <linux/if_ether.h>
  #include <linux/if_vlan.h>
  #include <linux/rculist.h>
27d79f3b1   Sachin Kamat   net: ipv4: Use PT...
42
  #include <linux/err.h>
c54419321   Pravin B Shelar   GRE: Refactor GRE...
43
44
45
46
47
48
49
50
51
52
53
54
55
56
  
  #include <net/sock.h>
  #include <net/ip.h>
  #include <net/icmp.h>
  #include <net/protocol.h>
  #include <net/ip_tunnels.h>
  #include <net/arp.h>
  #include <net/checksum.h>
  #include <net/dsfield.h>
  #include <net/inet_ecn.h>
  #include <net/xfrm.h>
  #include <net/net_namespace.h>
  #include <net/netns/generic.h>
  #include <net/rtnetlink.h>
563284865   Tom Herbert   net: Changes to i...
57
  #include <net/udp.h>
cfc7381b3   Alexei Starovoitov   ip_tunnel: add co...
58
  #include <net/dst_metadata.h>
63487babf   Tom Herbert   net: Move fou_bui...
59

c54419321   Pravin B Shelar   GRE: Refactor GRE...
60
61
62
63
64
  #if IS_ENABLED(CONFIG_IPV6)
  #include <net/ipv6.h>
  #include <net/ip6_fib.h>
  #include <net/ip6_route.h>
  #endif
967680e02   Duan Jiong   ipv4: remove the ...
65
  static unsigned int ip_tunnel_hash(__be32 key, __be32 remote)
c54419321   Pravin B Shelar   GRE: Refactor GRE...
66
67
68
69
  {
  	return hash_32((__force u32)key ^ (__force u32)remote,
  			 IP_TNL_HASH_BITS);
  }
c54419321   Pravin B Shelar   GRE: Refactor GRE...
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
  static bool ip_tunnel_key_match(const struct ip_tunnel_parm *p,
  				__be16 flags, __be32 key)
  {
  	if (p->i_flags & TUNNEL_KEY) {
  		if (flags & TUNNEL_KEY)
  			return key == p->i_key;
  		else
  			/* key expected, none present */
  			return false;
  	} else
  		return !(flags & TUNNEL_KEY);
  }
  
  /* Fallback tunnel: no source, no destination, no key, no options
  
     Tunnel hash table:
     We require exact key match i.e. if a key is present in packet
     it will match only tunnel with the same key; if it is not present,
     it will match only keyless tunnel.
  
     All keysless packets, if not matched configured keyless tunnels
     will match fallback tunnel.
     Given src, dst and key, find appropriate for input tunnel.
  */
  struct ip_tunnel *ip_tunnel_lookup(struct ip_tunnel_net *itn,
  				   int link, __be16 flags,
  				   __be32 remote, __be32 local,
  				   __be32 key)
  {
  	unsigned int hash;
  	struct ip_tunnel *t, *cand = NULL;
  	struct hlist_head *head;
967680e02   Duan Jiong   ipv4: remove the ...
102
  	hash = ip_tunnel_hash(key, remote);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
  	head = &itn->tunnels[hash];
  
  	hlist_for_each_entry_rcu(t, head, hash_node) {
  		if (local != t->parms.iph.saddr ||
  		    remote != t->parms.iph.daddr ||
  		    !(t->dev->flags & IFF_UP))
  			continue;
  
  		if (!ip_tunnel_key_match(&t->parms, flags, key))
  			continue;
  
  		if (t->parms.link == link)
  			return t;
  		else
  			cand = t;
  	}
  
  	hlist_for_each_entry_rcu(t, head, hash_node) {
  		if (remote != t->parms.iph.daddr ||
e0056593b   Dmitry Popov   ip_tunnel: fix ip...
122
  		    t->parms.iph.saddr != 0 ||
c54419321   Pravin B Shelar   GRE: Refactor GRE...
123
124
125
126
127
128
129
130
131
132
133
  		    !(t->dev->flags & IFF_UP))
  			continue;
  
  		if (!ip_tunnel_key_match(&t->parms, flags, key))
  			continue;
  
  		if (t->parms.link == link)
  			return t;
  		else if (!cand)
  			cand = t;
  	}
967680e02   Duan Jiong   ipv4: remove the ...
134
  	hash = ip_tunnel_hash(key, 0);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
135
136
137
  	head = &itn->tunnels[hash];
  
  	hlist_for_each_entry_rcu(t, head, hash_node) {
e0056593b   Dmitry Popov   ip_tunnel: fix ip...
138
139
140
141
142
  		if ((local != t->parms.iph.saddr || t->parms.iph.daddr != 0) &&
  		    (local != t->parms.iph.daddr || !ipv4_is_multicast(local)))
  			continue;
  
  		if (!(t->dev->flags & IFF_UP))
c54419321   Pravin B Shelar   GRE: Refactor GRE...
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
  			continue;
  
  		if (!ip_tunnel_key_match(&t->parms, flags, key))
  			continue;
  
  		if (t->parms.link == link)
  			return t;
  		else if (!cand)
  			cand = t;
  	}
  
  	if (flags & TUNNEL_NO_KEY)
  		goto skip_key_lookup;
  
  	hlist_for_each_entry_rcu(t, head, hash_node) {
  		if (t->parms.i_key != key ||
e0056593b   Dmitry Popov   ip_tunnel: fix ip...
159
160
  		    t->parms.iph.saddr != 0 ||
  		    t->parms.iph.daddr != 0 ||
c54419321   Pravin B Shelar   GRE: Refactor GRE...
161
162
163
164
165
166
167
168
169
170
171
172
  		    !(t->dev->flags & IFF_UP))
  			continue;
  
  		if (t->parms.link == link)
  			return t;
  		else if (!cand)
  			cand = t;
  	}
  
  skip_key_lookup:
  	if (cand)
  		return cand;
2e15ea390   Pravin B Shelar   ip_gre: Add suppo...
173
  	t = rcu_dereference(itn->collect_md_tun);
833a8b405   Haishuang Yan   ip_tunnel: fix ip...
174
  	if (t && t->dev->flags & IFF_UP)
2e15ea390   Pravin B Shelar   ip_gre: Add suppo...
175
  		return t;
c54419321   Pravin B Shelar   GRE: Refactor GRE...
176
177
  	if (itn->fb_tunnel_dev && itn->fb_tunnel_dev->flags & IFF_UP)
  		return netdev_priv(itn->fb_tunnel_dev);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
178
179
180
181
182
183
184
185
186
  	return NULL;
  }
  EXPORT_SYMBOL_GPL(ip_tunnel_lookup);
  
  static struct hlist_head *ip_bucket(struct ip_tunnel_net *itn,
  				    struct ip_tunnel_parm *parms)
  {
  	unsigned int h;
  	__be32 remote;
6d608f06e   Steffen Klassert   ip_tunnel: Make v...
187
  	__be32 i_key = parms->i_key;
c54419321   Pravin B Shelar   GRE: Refactor GRE...
188
189
190
191
192
  
  	if (parms->iph.daddr && !ipv4_is_multicast(parms->iph.daddr))
  		remote = parms->iph.daddr;
  	else
  		remote = 0;
6d608f06e   Steffen Klassert   ip_tunnel: Make v...
193
194
195
196
  	if (!(parms->i_flags & TUNNEL_KEY) && (parms->i_flags & VTI_ISVTI))
  		i_key = 0;
  
  	h = ip_tunnel_hash(i_key, remote);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
197
198
199
200
201
202
  	return &itn->tunnels[h];
  }
  
  static void ip_tunnel_add(struct ip_tunnel_net *itn, struct ip_tunnel *t)
  {
  	struct hlist_head *head = ip_bucket(itn, &t->parms);
2e15ea390   Pravin B Shelar   ip_gre: Add suppo...
203
204
  	if (t->collect_md)
  		rcu_assign_pointer(itn->collect_md_tun, t);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
205
206
  	hlist_add_head_rcu(&t->hash_node, head);
  }
2e15ea390   Pravin B Shelar   ip_gre: Add suppo...
207
  static void ip_tunnel_del(struct ip_tunnel_net *itn, struct ip_tunnel *t)
c54419321   Pravin B Shelar   GRE: Refactor GRE...
208
  {
2e15ea390   Pravin B Shelar   ip_gre: Add suppo...
209
210
  	if (t->collect_md)
  		rcu_assign_pointer(itn->collect_md_tun, NULL);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
211
212
213
214
215
216
217
218
219
220
  	hlist_del_init_rcu(&t->hash_node);
  }
  
  static struct ip_tunnel *ip_tunnel_find(struct ip_tunnel_net *itn,
  					struct ip_tunnel_parm *parms,
  					int type)
  {
  	__be32 remote = parms->iph.daddr;
  	__be32 local = parms->iph.saddr;
  	__be32 key = parms->i_key;
5ce54af1f   Dmitry Popov   ip_tunnel: fix i_...
221
  	__be16 flags = parms->i_flags;
c54419321   Pravin B Shelar   GRE: Refactor GRE...
222
223
224
225
226
227
228
  	int link = parms->link;
  	struct ip_tunnel *t = NULL;
  	struct hlist_head *head = ip_bucket(itn, parms);
  
  	hlist_for_each_entry_rcu(t, head, hash_node) {
  		if (local == t->parms.iph.saddr &&
  		    remote == t->parms.iph.daddr &&
c54419321   Pravin B Shelar   GRE: Refactor GRE...
229
  		    link == t->parms.link &&
5ce54af1f   Dmitry Popov   ip_tunnel: fix i_...
230
231
  		    type == t->dev->type &&
  		    ip_tunnel_key_match(&t->parms, flags, key))
c54419321   Pravin B Shelar   GRE: Refactor GRE...
232
233
234
235
236
237
238
239
240
241
242
243
244
  			break;
  	}
  	return t;
  }
  
  static struct net_device *__ip_tunnel_create(struct net *net,
  					     const struct rtnl_link_ops *ops,
  					     struct ip_tunnel_parm *parms)
  {
  	int err;
  	struct ip_tunnel *tunnel;
  	struct net_device *dev;
  	char name[IFNAMSIZ];
6816295fe   Eric Dumazet   ip_tunnel: better...
245
246
247
248
  	err = -E2BIG;
  	if (parms->name[0]) {
  		if (!dev_valid_name(parms->name))
  			goto failed;
c54419321   Pravin B Shelar   GRE: Refactor GRE...
249
  		strlcpy(name, parms->name, IFNAMSIZ);
6816295fe   Eric Dumazet   ip_tunnel: better...
250
251
  	} else {
  		if (strlen(ops->kind) > (IFNAMSIZ - 3))
c54419321   Pravin B Shelar   GRE: Refactor GRE...
252
  			goto failed;
bb1d0ac3e   Sultan Alsawaf   ip_tunnel: Fix na...
253
254
  		strcpy(name, ops->kind);
  		strcat(name, "%d");
c54419321   Pravin B Shelar   GRE: Refactor GRE...
255
256
257
  	}
  
  	ASSERT_RTNL();
c835a6773   Tom Gundersen   net: set name_ass...
258
  	dev = alloc_netdev(ops->priv_size, name, NET_NAME_UNKNOWN, ops->setup);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
259
260
261
262
263
264
265
266
267
268
  	if (!dev) {
  		err = -ENOMEM;
  		goto failed;
  	}
  	dev_net_set(dev, net);
  
  	dev->rtnl_link_ops = ops;
  
  	tunnel = netdev_priv(dev);
  	tunnel->parms = *parms;
5e6700b3b   Nicolas Dichtel   sit: add support ...
269
  	tunnel->net = net;
c54419321   Pravin B Shelar   GRE: Refactor GRE...
270
271
272
273
274
275
276
277
278
279
280
281
  
  	err = register_netdevice(dev);
  	if (err)
  		goto failed_free;
  
  	return dev;
  
  failed_free:
  	free_netdev(dev);
  failed:
  	return ERR_PTR(err);
  }
7d442fab0   Tom Herbert   ipv4: Cache dst i...
282
283
284
  static inline void init_tunnel_flow(struct flowi4 *fl4,
  				    int proto,
  				    __be32 daddr, __be32 saddr,
9830ad4c6   Craig Gallek   ip_tunnel: Allow ...
285
286
  				    __be32 key, __u8 tos, int oif,
  				    __u32 mark)
c54419321   Pravin B Shelar   GRE: Refactor GRE...
287
288
289
290
291
292
293
294
  {
  	memset(fl4, 0, sizeof(*fl4));
  	fl4->flowi4_oif = oif;
  	fl4->daddr = daddr;
  	fl4->saddr = saddr;
  	fl4->flowi4_tos = tos;
  	fl4->flowi4_proto = proto;
  	fl4->fl4_gre_key = key;
9830ad4c6   Craig Gallek   ip_tunnel: Allow ...
295
  	fl4->flowi4_mark = mark;
c54419321   Pravin B Shelar   GRE: Refactor GRE...
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
  }
  
  static int ip_tunnel_bind_dev(struct net_device *dev)
  {
  	struct net_device *tdev = NULL;
  	struct ip_tunnel *tunnel = netdev_priv(dev);
  	const struct iphdr *iph;
  	int hlen = LL_MAX_HEADER;
  	int mtu = ETH_DATA_LEN;
  	int t_hlen = tunnel->hlen + sizeof(struct iphdr);
  
  	iph = &tunnel->parms.iph;
  
  	/* Guess output device to choose reasonable mtu and needed_headroom */
  	if (iph->daddr) {
  		struct flowi4 fl4;
  		struct rtable *rt;
7d442fab0   Tom Herbert   ipv4: Cache dst i...
313
314
  		init_tunnel_flow(&fl4, iph->protocol, iph->daddr,
  				 iph->saddr, tunnel->parms.o_key,
9830ad4c6   Craig Gallek   ip_tunnel: Allow ...
315
316
  				 RT_TOS(iph->tos), tunnel->parms.link,
  				 tunnel->fwmark);
7d442fab0   Tom Herbert   ipv4: Cache dst i...
317
  		rt = ip_route_output_key(tunnel->net, &fl4);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
318
319
320
321
322
323
  		if (!IS_ERR(rt)) {
  			tdev = rt->dst.dev;
  			ip_rt_put(rt);
  		}
  		if (dev->type != ARPHRD_ETHER)
  			dev->flags |= IFF_POINTOPOINT;
f27337e16   Paolo Abeni   ip_tunnel: fix pr...
324
325
  
  		dst_cache_reset(&tunnel->dst_cache);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
326
327
328
  	}
  
  	if (!tdev && tunnel->parms.link)
6c742e714   Nicolas Dichtel   ipip: add x-netns...
329
  		tdev = __dev_get_by_index(tunnel->net, tunnel->parms.link);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
330
331
332
333
334
  
  	if (tdev) {
  		hlen = tdev->hard_header_len + tdev->needed_headroom;
  		mtu = tdev->mtu;
  	}
c54419321   Pravin B Shelar   GRE: Refactor GRE...
335
336
337
  
  	dev->needed_headroom = t_hlen + hlen;
  	mtu -= (dev->hard_header_len + t_hlen);
57dfc3d10   Eric Dumazet   ipv4: igmp: guard...
338
339
  	if (mtu < IPV4_MIN_MTU)
  		mtu = IPV4_MIN_MTU;
c54419321   Pravin B Shelar   GRE: Refactor GRE...
340
341
342
343
344
345
346
347
  
  	return mtu;
  }
  
  static struct ip_tunnel *ip_tunnel_create(struct net *net,
  					  struct ip_tunnel_net *itn,
  					  struct ip_tunnel_parm *parms)
  {
4929fd8cb   Julia Lawall   ip_tunnel: delete...
348
  	struct ip_tunnel *nt;
c54419321   Pravin B Shelar   GRE: Refactor GRE...
349
  	struct net_device *dev;
b96f9afee   Jarod Wilson   ipv4/6: use core ...
350
  	int t_hlen;
c54419321   Pravin B Shelar   GRE: Refactor GRE...
351
352
  
  	BUG_ON(!itn->fb_tunnel_dev);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
353
354
  	dev = __ip_tunnel_create(net, itn->fb_tunnel_dev->rtnl_link_ops, parms);
  	if (IS_ERR(dev))
6dd3c9ec2   Florian Westphal   ip_tunnel: return...
355
  		return ERR_CAST(dev);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
356
357
358
359
  
  	dev->mtu = ip_tunnel_bind_dev(dev);
  
  	nt = netdev_priv(dev);
b96f9afee   Jarod Wilson   ipv4/6: use core ...
360
361
362
  	t_hlen = nt->hlen + sizeof(struct iphdr);
  	dev->min_mtu = ETH_MIN_MTU;
  	dev->max_mtu = 0xFFF8 - dev->hard_header_len - t_hlen;
c54419321   Pravin B Shelar   GRE: Refactor GRE...
363
364
365
366
367
  	ip_tunnel_add(itn, nt);
  	return nt;
  }
  
  int ip_tunnel_rcv(struct ip_tunnel *tunnel, struct sk_buff *skb,
2e15ea390   Pravin B Shelar   ip_gre: Add suppo...
368
369
  		  const struct tnl_ptk_info *tpi, struct metadata_dst *tun_dst,
  		  bool log_ecn_error)
c54419321   Pravin B Shelar   GRE: Refactor GRE...
370
  {
8f84985fe   Li RongQing   net: unify the pc...
371
  	struct pcpu_sw_netstats *tstats;
c54419321   Pravin B Shelar   GRE: Refactor GRE...
372
373
  	const struct iphdr *iph = ip_hdr(skb);
  	int err;
c54419321   Pravin B Shelar   GRE: Refactor GRE...
374
375
  #ifdef CONFIG_NET_IPGRE_BROADCAST
  	if (ipv4_is_multicast(iph->daddr)) {
c54419321   Pravin B Shelar   GRE: Refactor GRE...
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
  		tunnel->dev->stats.multicast++;
  		skb->pkt_type = PACKET_BROADCAST;
  	}
  #endif
  
  	if ((!(tpi->flags&TUNNEL_CSUM) &&  (tunnel->parms.i_flags&TUNNEL_CSUM)) ||
  	     ((tpi->flags&TUNNEL_CSUM) && !(tunnel->parms.i_flags&TUNNEL_CSUM))) {
  		tunnel->dev->stats.rx_crc_errors++;
  		tunnel->dev->stats.rx_errors++;
  		goto drop;
  	}
  
  	if (tunnel->parms.i_flags&TUNNEL_SEQ) {
  		if (!(tpi->flags&TUNNEL_SEQ) ||
  		    (tunnel->i_seqno && (s32)(ntohl(tpi->seq) - tunnel->i_seqno) < 0)) {
  			tunnel->dev->stats.rx_fifo_errors++;
  			tunnel->dev->stats.rx_errors++;
  			goto drop;
  		}
  		tunnel->i_seqno = ntohl(tpi->seq) + 1;
  	}
e96f2e7c4   Ying Cai   ip_tunnel: Set ne...
397
  	skb_reset_network_header(skb);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
  	err = IP_ECN_decapsulate(iph, skb);
  	if (unlikely(err)) {
  		if (log_ecn_error)
  			net_info_ratelimited("non-ECT from %pI4 with TOS=%#x
  ",
  					&iph->saddr, iph->tos);
  		if (err > 1) {
  			++tunnel->dev->stats.rx_frame_errors;
  			++tunnel->dev->stats.rx_errors;
  			goto drop;
  		}
  	}
  
  	tstats = this_cpu_ptr(tunnel->dev->tstats);
  	u64_stats_update_begin(&tstats->syncp);
  	tstats->rx_packets++;
  	tstats->rx_bytes += skb->len;
  	u64_stats_update_end(&tstats->syncp);
81b9eab5e   Alexei Starovoitov   core/dev: do not ...
416
  	skb_scrub_packet(skb, !net_eq(tunnel->net, dev_net(tunnel->dev)));
3d7b46cd2   Pravin B Shelar   ip_tunnel: push g...
417
418
419
420
421
422
  	if (tunnel->dev->type == ARPHRD_ETHER) {
  		skb->protocol = eth_type_trans(skb, tunnel->dev);
  		skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN);
  	} else {
  		skb->dev = tunnel->dev;
  	}
64261f230   Nicolas Dichtel   dev: move skb_scr...
423

2e15ea390   Pravin B Shelar   ip_gre: Add suppo...
424
425
  	if (tun_dst)
  		skb_dst_set(skb, (struct dst_entry *)tun_dst);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
426
427
428
429
  	gro_cells_receive(&tunnel->gro_cells, skb);
  	return 0;
  
  drop:
469f87e15   Haishuang Yan   ip_tunnel: fix po...
430
431
  	if (tun_dst)
  		dst_release((struct dst_entry *)tun_dst);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
432
433
434
435
  	kfree_skb(skb);
  	return 0;
  }
  EXPORT_SYMBOL_GPL(ip_tunnel_rcv);
a8c5f90fb   Tom Herbert   ip_tunnel: Ops re...
436
437
438
  int ip_tunnel_encap_add_ops(const struct ip_tunnel_encap_ops *ops,
  			    unsigned int num)
  {
bb1553c80   Thomas Graf   ip_tunnel: Add sa...
439
440
  	if (num >= MAX_IPTUN_ENCAP_OPS)
  		return -ERANGE;
a8c5f90fb   Tom Herbert   ip_tunnel: Ops re...
441
442
443
  	return !cmpxchg((const struct ip_tunnel_encap_ops **)
  			&iptun_encaps[num],
  			NULL, ops) ? 0 : -1;
563284865   Tom Herbert   net: Changes to i...
444
  }
a8c5f90fb   Tom Herbert   ip_tunnel: Ops re...
445
446
447
448
449
450
  EXPORT_SYMBOL(ip_tunnel_encap_add_ops);
  
  int ip_tunnel_encap_del_ops(const struct ip_tunnel_encap_ops *ops,
  			    unsigned int num)
  {
  	int ret;
bb1553c80   Thomas Graf   ip_tunnel: Add sa...
451
452
  	if (num >= MAX_IPTUN_ENCAP_OPS)
  		return -ERANGE;
a8c5f90fb   Tom Herbert   ip_tunnel: Ops re...
453
454
455
456
457
458
459
460
461
  	ret = (cmpxchg((const struct ip_tunnel_encap_ops **)
  		       &iptun_encaps[num],
  		       ops, NULL) == ops) ? 0 : -1;
  
  	synchronize_net();
  
  	return ret;
  }
  EXPORT_SYMBOL(ip_tunnel_encap_del_ops);
563284865   Tom Herbert   net: Changes to i...
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
  
  int ip_tunnel_encap_setup(struct ip_tunnel *t,
  			  struct ip_tunnel_encap *ipencap)
  {
  	int hlen;
  
  	memset(&t->encap, 0, sizeof(t->encap));
  
  	hlen = ip_encap_hlen(ipencap);
  	if (hlen < 0)
  		return hlen;
  
  	t->encap.type = ipencap->type;
  	t->encap.sport = ipencap->sport;
  	t->encap.dport = ipencap->dport;
  	t->encap.flags = ipencap->flags;
  
  	t->encap_hlen = hlen;
  	t->hlen = t->encap_hlen + t->tun_hlen;
  
  	return 0;
  }
  EXPORT_SYMBOL_GPL(ip_tunnel_encap_setup);
23a3647bc   Pravin B Shelar   ip_tunnels: Use s...
485
  static int tnl_update_pmtu(struct net_device *dev, struct sk_buff *skb,
fc24f2b20   Timo Teräs   ip_tunnel: fix ip...
486
487
  			    struct rtable *rt, __be16 df,
  			    const struct iphdr *inner_iph)
23a3647bc   Pravin B Shelar   ip_tunnels: Use s...
488
489
  {
  	struct ip_tunnel *tunnel = netdev_priv(dev);
8c91e162e   Alexander Duyck   gre: Fix MTU sizi...
490
  	int pkt_size = skb->len - tunnel->hlen - dev->hard_header_len;
23a3647bc   Pravin B Shelar   ip_tunnels: Use s...
491
492
493
494
495
496
497
  	int mtu;
  
  	if (df)
  		mtu = dst_mtu(&rt->dst) - dev->hard_header_len
  					- sizeof(struct iphdr) - tunnel->hlen;
  	else
  		mtu = skb_dst(skb) ? dst_mtu(skb_dst(skb)) : dev->mtu;
6a3c946b2   Nicolas Dichtel   net: don't call u...
498
  	skb_dst_update_pmtu(skb, mtu);
23a3647bc   Pravin B Shelar   ip_tunnels: Use s...
499
500
501
  
  	if (skb->protocol == htons(ETH_P_IP)) {
  		if (!skb_is_gso(skb) &&
fc24f2b20   Timo Teräs   ip_tunnel: fix ip...
502
503
  		    (inner_iph->frag_off & htons(IP_DF)) &&
  		    mtu < pkt_size) {
23a3647bc   Pravin B Shelar   ip_tunnels: Use s...
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
  			memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
  			icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));
  			return -E2BIG;
  		}
  	}
  #if IS_ENABLED(CONFIG_IPV6)
  	else if (skb->protocol == htons(ETH_P_IPV6)) {
  		struct rt6_info *rt6 = (struct rt6_info *)skb_dst(skb);
  
  		if (rt6 && mtu < dst_mtu(skb_dst(skb)) &&
  			   mtu >= IPV6_MIN_MTU) {
  			if ((tunnel->parms.iph.daddr &&
  			    !ipv4_is_multicast(tunnel->parms.iph.daddr)) ||
  			    rt6->rt6i_dst.plen == 128) {
  				rt6->rt6i_flags |= RTF_MODIFIED;
  				dst_metric_set(skb_dst(skb), RTAX_MTU, mtu);
  			}
  		}
  
  		if (!skb_is_gso(skb) && mtu >= IPV6_MIN_MTU &&
  					mtu < pkt_size) {
  			icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
  			return -E2BIG;
  		}
  	}
  #endif
  	return 0;
  }
cfc7381b3   Alexei Starovoitov   ip_tunnel: add co...
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
  void ip_md_tunnel_xmit(struct sk_buff *skb, struct net_device *dev, u8 proto)
  {
  	struct ip_tunnel *tunnel = netdev_priv(dev);
  	u32 headroom = sizeof(struct iphdr);
  	struct ip_tunnel_info *tun_info;
  	const struct ip_tunnel_key *key;
  	const struct iphdr *inner_iph;
  	struct rtable *rt;
  	struct flowi4 fl4;
  	__be16 df = 0;
  	u8 tos, ttl;
  
  	tun_info = skb_tunnel_info(skb);
  	if (unlikely(!tun_info || !(tun_info->mode & IP_TUNNEL_INFO_TX) ||
  		     ip_tunnel_info_af(tun_info) != AF_INET))
  		goto tx_error;
  	key = &tun_info->key;
  	memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
  	inner_iph = (const struct iphdr *)skb_inner_network_header(skb);
  	tos = key->tos;
  	if (tos == 1) {
  		if (skb->protocol == htons(ETH_P_IP))
  			tos = inner_iph->tos;
  		else if (skb->protocol == htons(ETH_P_IPV6))
  			tos = ipv6_get_dsfield((const struct ipv6hdr *)inner_iph);
  	}
  	init_tunnel_flow(&fl4, proto, key->u.ipv4.dst, key->u.ipv4.src, 0,
9830ad4c6   Craig Gallek   ip_tunnel: Allow ...
559
  			 RT_TOS(tos), tunnel->parms.link, tunnel->fwmark);
cfc7381b3   Alexei Starovoitov   ip_tunnel: add co...
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
  	if (tunnel->encap.type != TUNNEL_ENCAP_NONE)
  		goto tx_error;
  	rt = ip_route_output_key(tunnel->net, &fl4);
  	if (IS_ERR(rt)) {
  		dev->stats.tx_carrier_errors++;
  		goto tx_error;
  	}
  	if (rt->dst.dev == dev) {
  		ip_rt_put(rt);
  		dev->stats.collisions++;
  		goto tx_error;
  	}
  	tos = ip_tunnel_ecn_encap(tos, inner_iph, skb);
  	ttl = key->ttl;
  	if (ttl == 0) {
  		if (skb->protocol == htons(ETH_P_IP))
  			ttl = inner_iph->ttl;
  		else if (skb->protocol == htons(ETH_P_IPV6))
  			ttl = ((const struct ipv6hdr *)inner_iph)->hop_limit;
  		else
  			ttl = ip4_dst_hoplimit(&rt->dst);
  	}
  	if (key->tun_flags & TUNNEL_DONT_FRAGMENT)
  		df = htons(IP_DF);
  	else if (skb->protocol == htons(ETH_P_IP))
  		df = inner_iph->frag_off & htons(IP_DF);
  	headroom += LL_RESERVED_SPACE(rt->dst.dev) + rt->dst.header_len;
  	if (headroom > dev->needed_headroom)
  		dev->needed_headroom = headroom;
  
  	if (skb_cow_head(skb, dev->needed_headroom)) {
  		ip_rt_put(rt);
  		goto tx_dropped;
  	}
0f693f199   Haishuang Yan   ip_tunnel: fix se...
594
595
  	iptunnel_xmit(NULL, rt, skb, fl4.saddr, fl4.daddr, proto, tos, ttl,
  		      df, !net_eq(tunnel->net, dev_net(dev)));
cfc7381b3   Alexei Starovoitov   ip_tunnel: add co...
596
597
598
599
600
601
602
603
604
605
  	return;
  tx_error:
  	dev->stats.tx_errors++;
  	goto kfree;
  tx_dropped:
  	dev->stats.tx_dropped++;
  kfree:
  	kfree_skb(skb);
  }
  EXPORT_SYMBOL_GPL(ip_md_tunnel_xmit);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
606
  void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
563284865   Tom Herbert   net: Changes to i...
607
  		    const struct iphdr *tnl_params, u8 protocol)
c54419321   Pravin B Shelar   GRE: Refactor GRE...
608
609
  {
  	struct ip_tunnel *tunnel = netdev_priv(dev);
deb33b68f   Paolo Abeni   ip_tunnel: be car...
610
  	unsigned int inner_nhdr_len = 0;
c54419321   Pravin B Shelar   GRE: Refactor GRE...
611
  	const struct iphdr *inner_iph;
c54419321   Pravin B Shelar   GRE: Refactor GRE...
612
613
614
  	struct flowi4 fl4;
  	u8     tos, ttl;
  	__be16 df;
b045d37bd   Eric Dumazet   ip_tunnel: fix pa...
615
  	struct rtable *rt;		/* Route to the other host */
c54419321   Pravin B Shelar   GRE: Refactor GRE...
616
617
  	unsigned int max_headroom;	/* The extra header space needed */
  	__be32 dst;
22fb22eae   Timo Teräs   ipv4: ip_tunnels:...
618
  	bool connected;
c54419321   Pravin B Shelar   GRE: Refactor GRE...
619

deb33b68f   Paolo Abeni   ip_tunnel: be car...
620
621
622
623
624
625
626
  	/* ensure we can access the inner net header, for several users below */
  	if (skb->protocol == htons(ETH_P_IP))
  		inner_nhdr_len = sizeof(struct iphdr);
  	else if (skb->protocol == htons(ETH_P_IPV6))
  		inner_nhdr_len = sizeof(struct ipv6hdr);
  	if (unlikely(!pskb_may_pull(skb, inner_nhdr_len)))
  		goto tx_error;
c54419321   Pravin B Shelar   GRE: Refactor GRE...
627
  	inner_iph = (const struct iphdr *)skb_inner_network_header(skb);
22fb22eae   Timo Teräs   ipv4: ip_tunnels:...
628
  	connected = (tunnel->parms.iph.daddr != 0);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
629

5146d1f15   Bernie Harris   tunnel: Clear IPC...
630
  	memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
c54419321   Pravin B Shelar   GRE: Refactor GRE...
631
632
633
  	dst = tnl_params->daddr;
  	if (dst == 0) {
  		/* NBMA tunnel */
51456b291   Ian Morris   ipv4: coding styl...
634
  		if (!skb_dst(skb)) {
c54419321   Pravin B Shelar   GRE: Refactor GRE...
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
  			dev->stats.tx_fifo_errors++;
  			goto tx_error;
  		}
  
  		if (skb->protocol == htons(ETH_P_IP)) {
  			rt = skb_rtable(skb);
  			dst = rt_nexthop(rt, inner_iph->daddr);
  		}
  #if IS_ENABLED(CONFIG_IPV6)
  		else if (skb->protocol == htons(ETH_P_IPV6)) {
  			const struct in6_addr *addr6;
  			struct neighbour *neigh;
  			bool do_tx_error_icmp;
  			int addr_type;
  
  			neigh = dst_neigh_lookup(skb_dst(skb),
  						 &ipv6_hdr(skb)->daddr);
51456b291   Ian Morris   ipv4: coding styl...
652
  			if (!neigh)
c54419321   Pravin B Shelar   GRE: Refactor GRE...
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
  				goto tx_error;
  
  			addr6 = (const struct in6_addr *)&neigh->primary_key;
  			addr_type = ipv6_addr_type(addr6);
  
  			if (addr_type == IPV6_ADDR_ANY) {
  				addr6 = &ipv6_hdr(skb)->daddr;
  				addr_type = ipv6_addr_type(addr6);
  			}
  
  			if ((addr_type & IPV6_ADDR_COMPATv4) == 0)
  				do_tx_error_icmp = true;
  			else {
  				do_tx_error_icmp = false;
  				dst = addr6->s6_addr32[3];
  			}
  			neigh_release(neigh);
  			if (do_tx_error_icmp)
  				goto tx_error_icmp;
  		}
  #endif
  		else
  			goto tx_error;
7d442fab0   Tom Herbert   ipv4: Cache dst i...
676
677
  
  		connected = false;
c54419321   Pravin B Shelar   GRE: Refactor GRE...
678
679
680
681
682
  	}
  
  	tos = tnl_params->tos;
  	if (tos & 0x1) {
  		tos &= ~0x1;
7d442fab0   Tom Herbert   ipv4: Cache dst i...
683
  		if (skb->protocol == htons(ETH_P_IP)) {
c54419321   Pravin B Shelar   GRE: Refactor GRE...
684
  			tos = inner_iph->tos;
7d442fab0   Tom Herbert   ipv4: Cache dst i...
685
686
  			connected = false;
  		} else if (skb->protocol == htons(ETH_P_IPV6)) {
c54419321   Pravin B Shelar   GRE: Refactor GRE...
687
  			tos = ipv6_get_dsfield((const struct ipv6hdr *)inner_iph);
7d442fab0   Tom Herbert   ipv4: Cache dst i...
688
689
  			connected = false;
  		}
c54419321   Pravin B Shelar   GRE: Refactor GRE...
690
  	}
7d442fab0   Tom Herbert   ipv4: Cache dst i...
691
  	init_tunnel_flow(&fl4, protocol, dst, tnl_params->saddr,
9830ad4c6   Craig Gallek   ip_tunnel: Allow ...
692
693
  			 tunnel->parms.o_key, RT_TOS(tos), tunnel->parms.link,
  			 tunnel->fwmark);
7d442fab0   Tom Herbert   ipv4: Cache dst i...
694

563284865   Tom Herbert   net: Changes to i...
695
696
  	if (ip_tunnel_encap(skb, tunnel, &protocol, &fl4) < 0)
  		goto tx_error;
e09acddf8   Paolo Abeni   ip_tunnel: replac...
697
698
  	rt = connected ? dst_cache_get_ip4(&tunnel->dst_cache, &fl4.saddr) :
  			 NULL;
7d442fab0   Tom Herbert   ipv4: Cache dst i...
699
700
701
702
703
704
705
706
707
  
  	if (!rt) {
  		rt = ip_route_output_key(tunnel->net, &fl4);
  
  		if (IS_ERR(rt)) {
  			dev->stats.tx_carrier_errors++;
  			goto tx_error;
  		}
  		if (connected)
e09acddf8   Paolo Abeni   ip_tunnel: replac...
708
709
  			dst_cache_set_ip4(&tunnel->dst_cache, &rt->dst,
  					  fl4.saddr);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
710
  	}
7d442fab0   Tom Herbert   ipv4: Cache dst i...
711

0e6fbc5b6   Pravin B Shelar   ip_tunnels: exten...
712
  	if (rt->dst.dev == dev) {
c54419321   Pravin B Shelar   GRE: Refactor GRE...
713
714
715
716
  		ip_rt_put(rt);
  		dev->stats.collisions++;
  		goto tx_error;
  	}
c54419321   Pravin B Shelar   GRE: Refactor GRE...
717

fc24f2b20   Timo Teräs   ip_tunnel: fix ip...
718
  	if (tnl_update_pmtu(dev, skb, rt, tnl_params->frag_off, inner_iph)) {
23a3647bc   Pravin B Shelar   ip_tunnels: Use s...
719
720
  		ip_rt_put(rt);
  		goto tx_error;
c54419321   Pravin B Shelar   GRE: Refactor GRE...
721
  	}
c54419321   Pravin B Shelar   GRE: Refactor GRE...
722
723
724
725
726
727
728
729
730
731
  
  	if (tunnel->err_count > 0) {
  		if (time_before(jiffies,
  				tunnel->err_time + IPTUNNEL_ERR_TIMEO)) {
  			tunnel->err_count--;
  
  			dst_link_failure(skb);
  		} else
  			tunnel->err_count = 0;
  	}
d4a71b155   Pravin B Shelar   ip_tunnel: Do not...
732
  	tos = ip_tunnel_ecn_encap(tos, inner_iph, skb);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
733
734
735
736
737
738
739
740
741
742
743
  	ttl = tnl_params->ttl;
  	if (ttl == 0) {
  		if (skb->protocol == htons(ETH_P_IP))
  			ttl = inner_iph->ttl;
  #if IS_ENABLED(CONFIG_IPV6)
  		else if (skb->protocol == htons(ETH_P_IPV6))
  			ttl = ((const struct ipv6hdr *)inner_iph)->hop_limit;
  #endif
  		else
  			ttl = ip4_dst_hoplimit(&rt->dst);
  	}
23a3647bc   Pravin B Shelar   ip_tunnels: Use s...
744
  	df = tnl_params->frag_off;
22a59be8b   Philip Prindeville   net: ipv4: Add ab...
745
  	if (skb->protocol == htons(ETH_P_IP) && !tunnel->ignore_df)
23a3647bc   Pravin B Shelar   ip_tunnels: Use s...
746
  		df |= (inner_iph->frag_off&htons(IP_DF));
0e6fbc5b6   Pravin B Shelar   ip_tunnels: exten...
747
  	max_headroom = LL_RESERVED_SPACE(rt->dst.dev) + sizeof(struct iphdr)
7371e0221   Tom Herbert   ip_tunnel: Accoun...
748
  			+ rt->dst.header_len + ip_encap_hlen(&tunnel->encap);
3e08f4a72   Steffen Klassert   ip_tunnel: Fix a ...
749
  	if (max_headroom > dev->needed_headroom)
c54419321   Pravin B Shelar   GRE: Refactor GRE...
750
  		dev->needed_headroom = max_headroom;
3e08f4a72   Steffen Klassert   ip_tunnel: Fix a ...
751
752
  
  	if (skb_cow_head(skb, dev->needed_headroom)) {
586d5fc86   Dmitry Popov   ip_tunnel: fix po...
753
  		ip_rt_put(rt);
3e08f4a72   Steffen Klassert   ip_tunnel: Fix a ...
754
  		dev->stats.tx_dropped++;
3acfa1e73   Eric Dumazet   ipv4: be friend w...
755
  		kfree_skb(skb);
3e08f4a72   Steffen Klassert   ip_tunnel: Fix a ...
756
  		return;
c54419321   Pravin B Shelar   GRE: Refactor GRE...
757
  	}
039f50629   Pravin B Shelar   ip_tunnel: Move s...
758
759
  	iptunnel_xmit(NULL, rt, skb, fl4.saddr, fl4.daddr, protocol, tos, ttl,
  		      df, !net_eq(tunnel->net, dev_net(dev)));
c54419321   Pravin B Shelar   GRE: Refactor GRE...
760
761
762
763
764
765
766
767
  	return;
  
  #if IS_ENABLED(CONFIG_IPV6)
  tx_error_icmp:
  	dst_link_failure(skb);
  #endif
  tx_error:
  	dev->stats.tx_errors++;
3acfa1e73   Eric Dumazet   ipv4: be friend w...
768
  	kfree_skb(skb);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
769
770
771
772
773
774
775
  }
  EXPORT_SYMBOL_GPL(ip_tunnel_xmit);
  
  static void ip_tunnel_update(struct ip_tunnel_net *itn,
  			     struct ip_tunnel *t,
  			     struct net_device *dev,
  			     struct ip_tunnel_parm *p,
9830ad4c6   Craig Gallek   ip_tunnel: Allow ...
776
777
  			     bool set_mtu,
  			     __u32 fwmark)
c54419321   Pravin B Shelar   GRE: Refactor GRE...
778
  {
2e15ea390   Pravin B Shelar   ip_gre: Add suppo...
779
  	ip_tunnel_del(itn, t);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
780
781
782
783
784
785
786
787
788
789
790
791
792
  	t->parms.iph.saddr = p->iph.saddr;
  	t->parms.iph.daddr = p->iph.daddr;
  	t->parms.i_key = p->i_key;
  	t->parms.o_key = p->o_key;
  	if (dev->type != ARPHRD_ETHER) {
  		memcpy(dev->dev_addr, &p->iph.saddr, 4);
  		memcpy(dev->broadcast, &p->iph.daddr, 4);
  	}
  	ip_tunnel_add(itn, t);
  
  	t->parms.iph.ttl = p->iph.ttl;
  	t->parms.iph.tos = p->iph.tos;
  	t->parms.iph.frag_off = p->iph.frag_off;
9830ad4c6   Craig Gallek   ip_tunnel: Allow ...
793
  	if (t->parms.link != p->link || t->fwmark != fwmark) {
c54419321   Pravin B Shelar   GRE: Refactor GRE...
794
795
796
  		int mtu;
  
  		t->parms.link = p->link;
9830ad4c6   Craig Gallek   ip_tunnel: Allow ...
797
  		t->fwmark = fwmark;
c54419321   Pravin B Shelar   GRE: Refactor GRE...
798
799
800
801
  		mtu = ip_tunnel_bind_dev(dev);
  		if (set_mtu)
  			dev->mtu = mtu;
  	}
e09acddf8   Paolo Abeni   ip_tunnel: replac...
802
  	dst_cache_reset(&t->dst_cache);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
803
804
805
806
807
808
  	netdev_state_change(dev);
  }
  
  int ip_tunnel_ioctl(struct net_device *dev, struct ip_tunnel_parm *p, int cmd)
  {
  	int err = 0;
8c923ce21   Nicolas Dichtel   ip_tunnel: use th...
809
810
811
  	struct ip_tunnel *t = netdev_priv(dev);
  	struct net *net = t->net;
  	struct ip_tunnel_net *itn = net_generic(net, t->ip_tnl_net_id);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
812
813
814
815
  
  	BUG_ON(!itn->fb_tunnel_dev);
  	switch (cmd) {
  	case SIOCGETTUNNEL:
8c923ce21   Nicolas Dichtel   ip_tunnel: use th...
816
  		if (dev == itn->fb_tunnel_dev) {
c54419321   Pravin B Shelar   GRE: Refactor GRE...
817
  			t = ip_tunnel_find(itn, p, itn->fb_tunnel_dev->type);
51456b291   Ian Morris   ipv4: coding styl...
818
  			if (!t)
8c923ce21   Nicolas Dichtel   ip_tunnel: use th...
819
820
  				t = netdev_priv(dev);
  		}
c54419321   Pravin B Shelar   GRE: Refactor GRE...
821
822
823
824
825
826
827
828
829
830
  		memcpy(p, &t->parms, sizeof(*p));
  		break;
  
  	case SIOCADDTUNNEL:
  	case SIOCCHGTUNNEL:
  		err = -EPERM;
  		if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
  			goto done;
  		if (p->iph.ttl)
  			p->iph.frag_off |= htons(IP_DF);
7c8e6b9c2   Dmitry Popov   ip_vti: Fix 'ip t...
831
832
833
834
835
836
  		if (!(p->i_flags & VTI_ISVTI)) {
  			if (!(p->i_flags & TUNNEL_KEY))
  				p->i_key = 0;
  			if (!(p->o_flags & TUNNEL_KEY))
  				p->o_key = 0;
  		}
c54419321   Pravin B Shelar   GRE: Refactor GRE...
837
838
  
  		t = ip_tunnel_find(itn, p, itn->fb_tunnel_dev->type);
d61746b2e   Steffen Klassert   ip_tunnel: Don't ...
839
840
841
842
843
844
845
846
  		if (cmd == SIOCADDTUNNEL) {
  			if (!t) {
  				t = ip_tunnel_create(net, itn, p);
  				err = PTR_ERR_OR_ZERO(t);
  				break;
  			}
  
  			err = -EEXIST;
ee30ef4d4   Duan Jiong   ip_tunnel: don't ...
847
  			break;
6dd3c9ec2   Florian Westphal   ip_tunnel: return...
848
  		}
c54419321   Pravin B Shelar   GRE: Refactor GRE...
849
  		if (dev != itn->fb_tunnel_dev && cmd == SIOCCHGTUNNEL) {
00db41243   Ian Morris   ipv4: coding styl...
850
  			if (t) {
c54419321   Pravin B Shelar   GRE: Refactor GRE...
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
  				if (t->dev != dev) {
  					err = -EEXIST;
  					break;
  				}
  			} else {
  				unsigned int nflags = 0;
  
  				if (ipv4_is_multicast(p->iph.daddr))
  					nflags = IFF_BROADCAST;
  				else if (p->iph.daddr)
  					nflags = IFF_POINTOPOINT;
  
  				if ((dev->flags^nflags)&(IFF_POINTOPOINT|IFF_BROADCAST)) {
  					err = -EINVAL;
  					break;
  				}
  
  				t = netdev_priv(dev);
  			}
  		}
  
  		if (t) {
  			err = 0;
9830ad4c6   Craig Gallek   ip_tunnel: Allow ...
874
  			ip_tunnel_update(itn, t, dev, p, true, 0);
6dd3c9ec2   Florian Westphal   ip_tunnel: return...
875
876
877
  		} else {
  			err = -ENOENT;
  		}
c54419321   Pravin B Shelar   GRE: Refactor GRE...
878
879
880
881
882
883
884
885
886
887
  		break;
  
  	case SIOCDELTUNNEL:
  		err = -EPERM;
  		if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
  			goto done;
  
  		if (dev == itn->fb_tunnel_dev) {
  			err = -ENOENT;
  			t = ip_tunnel_find(itn, p, itn->fb_tunnel_dev->type);
51456b291   Ian Morris   ipv4: coding styl...
888
  			if (!t)
c54419321   Pravin B Shelar   GRE: Refactor GRE...
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
  				goto done;
  			err = -EPERM;
  			if (t == netdev_priv(itn->fb_tunnel_dev))
  				goto done;
  			dev = t->dev;
  		}
  		unregister_netdevice(dev);
  		err = 0;
  		break;
  
  	default:
  		err = -EINVAL;
  	}
  
  done:
  	return err;
  }
  EXPORT_SYMBOL_GPL(ip_tunnel_ioctl);
7e059158d   David Wragg   vxlan, gre, genev...
907
  int __ip_tunnel_change_mtu(struct net_device *dev, int new_mtu, bool strict)
c54419321   Pravin B Shelar   GRE: Refactor GRE...
908
909
910
  {
  	struct ip_tunnel *tunnel = netdev_priv(dev);
  	int t_hlen = tunnel->hlen + sizeof(struct iphdr);
7e059158d   David Wragg   vxlan, gre, genev...
911
  	int max_mtu = 0xFFF8 - dev->hard_header_len - t_hlen;
c54419321   Pravin B Shelar   GRE: Refactor GRE...
912

b96f9afee   Jarod Wilson   ipv4/6: use core ...
913
  	if (new_mtu < ETH_MIN_MTU)
c54419321   Pravin B Shelar   GRE: Refactor GRE...
914
  		return -EINVAL;
7e059158d   David Wragg   vxlan, gre, genev...
915
916
917
918
919
920
921
  
  	if (new_mtu > max_mtu) {
  		if (strict)
  			return -EINVAL;
  
  		new_mtu = max_mtu;
  	}
c54419321   Pravin B Shelar   GRE: Refactor GRE...
922
923
924
  	dev->mtu = new_mtu;
  	return 0;
  }
7e059158d   David Wragg   vxlan, gre, genev...
925
926
927
928
929
930
  EXPORT_SYMBOL_GPL(__ip_tunnel_change_mtu);
  
  int ip_tunnel_change_mtu(struct net_device *dev, int new_mtu)
  {
  	return __ip_tunnel_change_mtu(dev, new_mtu, true);
  }
c54419321   Pravin B Shelar   GRE: Refactor GRE...
931
932
933
934
935
936
937
  EXPORT_SYMBOL_GPL(ip_tunnel_change_mtu);
  
  static void ip_tunnel_dev_free(struct net_device *dev)
  {
  	struct ip_tunnel *tunnel = netdev_priv(dev);
  
  	gro_cells_destroy(&tunnel->gro_cells);
e09acddf8   Paolo Abeni   ip_tunnel: replac...
938
  	dst_cache_destroy(&tunnel->dst_cache);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
939
  	free_percpu(dev->tstats);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
940
941
942
943
  }
  
  void ip_tunnel_dellink(struct net_device *dev, struct list_head *head)
  {
c54419321   Pravin B Shelar   GRE: Refactor GRE...
944
945
  	struct ip_tunnel *tunnel = netdev_priv(dev);
  	struct ip_tunnel_net *itn;
6c742e714   Nicolas Dichtel   ipip: add x-netns...
946
  	itn = net_generic(tunnel->net, tunnel->ip_tnl_net_id);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
947
948
  
  	if (itn->fb_tunnel_dev != dev) {
2e15ea390   Pravin B Shelar   ip_gre: Add suppo...
949
  		ip_tunnel_del(itn, netdev_priv(dev));
c54419321   Pravin B Shelar   GRE: Refactor GRE...
950
951
952
953
  		unregister_netdevice_queue(dev, head);
  	}
  }
  EXPORT_SYMBOL_GPL(ip_tunnel_dellink);
1728d4fab   Nicolas Dichtel   tunnels: advertis...
954
955
956
957
958
959
960
  struct net *ip_tunnel_get_link_net(const struct net_device *dev)
  {
  	struct ip_tunnel *tunnel = netdev_priv(dev);
  
  	return tunnel->net;
  }
  EXPORT_SYMBOL(ip_tunnel_get_link_net);
1e99584b9   Nicolas Dichtel   ipip,gre,vti,sit:...
961
962
963
964
965
966
967
  int ip_tunnel_get_iflink(const struct net_device *dev)
  {
  	struct ip_tunnel *tunnel = netdev_priv(dev);
  
  	return tunnel->parms.link;
  }
  EXPORT_SYMBOL(ip_tunnel_get_iflink);
c7d03a00b   Alexey Dobriyan   netns: make struc...
968
  int ip_tunnel_init_net(struct net *net, unsigned int ip_tnl_net_id,
c54419321   Pravin B Shelar   GRE: Refactor GRE...
969
970
971
972
  				  struct rtnl_link_ops *ops, char *devname)
  {
  	struct ip_tunnel_net *itn = net_generic(net, ip_tnl_net_id);
  	struct ip_tunnel_parm parms;
6261d983f   stephen hemminger   ip_tunnel: embed ...
973
  	unsigned int i;
c54419321   Pravin B Shelar   GRE: Refactor GRE...
974

6261d983f   stephen hemminger   ip_tunnel: embed ...
975
976
  	for (i = 0; i < IP_TNL_HASH_SIZE; i++)
  		INIT_HLIST_HEAD(&itn->tunnels[i]);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
977
978
979
980
981
  
  	if (!ops) {
  		itn->fb_tunnel_dev = NULL;
  		return 0;
  	}
6261d983f   stephen hemminger   ip_tunnel: embed ...
982

c54419321   Pravin B Shelar   GRE: Refactor GRE...
983
984
985
986
987
988
  	memset(&parms, 0, sizeof(parms));
  	if (devname)
  		strlcpy(parms.name, devname, IFNAMSIZ);
  
  	rtnl_lock();
  	itn->fb_tunnel_dev = __ip_tunnel_create(net, ops, &parms);
ea857f28a   Dan Carpenter   ipip: dereferenci...
989
990
991
  	/* FB netdevice is special: we have one, and only one per netns.
  	 * Allowing to move it to another netns is clearly unsafe.
  	 */
670132826   Steffen Klassert   ip_tunnel: Add fa...
992
  	if (!IS_ERR(itn->fb_tunnel_dev)) {
b4de77ade   Dan Carpenter   ipip: potential r...
993
  		itn->fb_tunnel_dev->features |= NETIF_F_NETNS_LOCAL;
78ff4be45   Steffen Klassert   ip_tunnel: Initia...
994
  		itn->fb_tunnel_dev->mtu = ip_tunnel_bind_dev(itn->fb_tunnel_dev);
670132826   Steffen Klassert   ip_tunnel: Add fa...
995
996
  		ip_tunnel_add(itn, netdev_priv(itn->fb_tunnel_dev));
  	}
b4de77ade   Dan Carpenter   ipip: potential r...
997
  	rtnl_unlock();
c54419321   Pravin B Shelar   GRE: Refactor GRE...
998

27d79f3b1   Sachin Kamat   net: ipv4: Use PT...
999
  	return PTR_ERR_OR_ZERO(itn->fb_tunnel_dev);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1000
1001
  }
  EXPORT_SYMBOL_GPL(ip_tunnel_init_net);
6c742e714   Nicolas Dichtel   ipip: add x-netns...
1002
1003
  static void ip_tunnel_destroy(struct ip_tunnel_net *itn, struct list_head *head,
  			      struct rtnl_link_ops *ops)
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1004
  {
6c742e714   Nicolas Dichtel   ipip: add x-netns...
1005
1006
  	struct net *net = dev_net(itn->fb_tunnel_dev);
  	struct net_device *dev, *aux;
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1007
  	int h;
6c742e714   Nicolas Dichtel   ipip: add x-netns...
1008
1009
1010
  	for_each_netdev_safe(net, dev, aux)
  		if (dev->rtnl_link_ops == ops)
  			unregister_netdevice_queue(dev, head);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1011
1012
1013
1014
1015
1016
  	for (h = 0; h < IP_TNL_HASH_SIZE; h++) {
  		struct ip_tunnel *t;
  		struct hlist_node *n;
  		struct hlist_head *thead = &itn->tunnels[h];
  
  		hlist_for_each_entry_safe(t, n, thead, hash_node)
6c742e714   Nicolas Dichtel   ipip: add x-netns...
1017
1018
1019
1020
1021
  			/* If dev is in the same netns, it has already
  			 * been added to the list by the previous loop.
  			 */
  			if (!net_eq(dev_net(t->dev), net))
  				unregister_netdevice_queue(t->dev, head);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1022
  	}
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1023
  }
6c742e714   Nicolas Dichtel   ipip: add x-netns...
1024
  void ip_tunnel_delete_net(struct ip_tunnel_net *itn, struct rtnl_link_ops *ops)
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1025
1026
1027
1028
  {
  	LIST_HEAD(list);
  
  	rtnl_lock();
6c742e714   Nicolas Dichtel   ipip: add x-netns...
1029
  	ip_tunnel_destroy(itn, &list, ops);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1030
1031
  	unregister_netdevice_many(&list);
  	rtnl_unlock();
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1032
1033
1034
1035
  }
  EXPORT_SYMBOL_GPL(ip_tunnel_delete_net);
  
  int ip_tunnel_newlink(struct net_device *dev, struct nlattr *tb[],
9830ad4c6   Craig Gallek   ip_tunnel: Allow ...
1036
  		      struct ip_tunnel_parm *p, __u32 fwmark)
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1037
1038
1039
1040
1041
1042
1043
1044
1045
  {
  	struct ip_tunnel *nt;
  	struct net *net = dev_net(dev);
  	struct ip_tunnel_net *itn;
  	int mtu;
  	int err;
  
  	nt = netdev_priv(dev);
  	itn = net_generic(net, nt->ip_tnl_net_id);
2e15ea390   Pravin B Shelar   ip_gre: Add suppo...
1046
1047
1048
1049
1050
1051
1052
  	if (nt->collect_md) {
  		if (rtnl_dereference(itn->collect_md_tun))
  			return -EEXIST;
  	} else {
  		if (ip_tunnel_find(itn, p, dev->type))
  			return -EEXIST;
  	}
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1053

5e6700b3b   Nicolas Dichtel   sit: add support ...
1054
  	nt->net = net;
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1055
  	nt->parms = *p;
9830ad4c6   Craig Gallek   ip_tunnel: Allow ...
1056
  	nt->fwmark = fwmark;
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1057
1058
1059
1060
1061
1062
1063
1064
  	err = register_netdevice(dev);
  	if (err)
  		goto out;
  
  	if (dev->type == ARPHRD_ETHER && !tb[IFLA_ADDRESS])
  		eth_hw_addr_random(dev);
  
  	mtu = ip_tunnel_bind_dev(dev);
34b6ba622   Stefano Brivio   ip_tunnel: Clamp ...
1065
1066
1067
1068
1069
1070
  	if (tb[IFLA_MTU]) {
  		unsigned int max = 0xfff8 - dev->hard_header_len - nt->hlen;
  
  		dev->mtu = clamp(dev->mtu, (unsigned int)ETH_MIN_MTU,
  				 (unsigned int)(max - sizeof(struct iphdr)));
  	} else {
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1071
  		dev->mtu = mtu;
34b6ba622   Stefano Brivio   ip_tunnel: Clamp ...
1072
  	}
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1073
1074
  
  	ip_tunnel_add(itn, nt);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1075
1076
1077
1078
1079
1080
  out:
  	return err;
  }
  EXPORT_SYMBOL_GPL(ip_tunnel_newlink);
  
  int ip_tunnel_changelink(struct net_device *dev, struct nlattr *tb[],
9830ad4c6   Craig Gallek   ip_tunnel: Allow ...
1081
  			 struct ip_tunnel_parm *p, __u32 fwmark)
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1082
  {
6c742e714   Nicolas Dichtel   ipip: add x-netns...
1083
  	struct ip_tunnel *t;
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1084
  	struct ip_tunnel *tunnel = netdev_priv(dev);
6c742e714   Nicolas Dichtel   ipip: add x-netns...
1085
  	struct net *net = tunnel->net;
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1086
1087
1088
1089
  	struct ip_tunnel_net *itn = net_generic(net, tunnel->ip_tnl_net_id);
  
  	if (dev == itn->fb_tunnel_dev)
  		return -EINVAL;
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1090
1091
1092
1093
1094
1095
  	t = ip_tunnel_find(itn, p, dev->type);
  
  	if (t) {
  		if (t->dev != dev)
  			return -EEXIST;
  	} else {
6c742e714   Nicolas Dichtel   ipip: add x-netns...
1096
  		t = tunnel;
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
  
  		if (dev->type != ARPHRD_ETHER) {
  			unsigned int nflags = 0;
  
  			if (ipv4_is_multicast(p->iph.daddr))
  				nflags = IFF_BROADCAST;
  			else if (p->iph.daddr)
  				nflags = IFF_POINTOPOINT;
  
  			if ((dev->flags ^ nflags) &
  			    (IFF_POINTOPOINT | IFF_BROADCAST))
  				return -EINVAL;
  		}
  	}
9830ad4c6   Craig Gallek   ip_tunnel: Allow ...
1111
  	ip_tunnel_update(itn, t, dev, p, !tb[IFLA_MTU], fwmark);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1112
1113
1114
1115
1116
1117
1118
1119
  	return 0;
  }
  EXPORT_SYMBOL_GPL(ip_tunnel_changelink);
  
  int ip_tunnel_init(struct net_device *dev)
  {
  	struct ip_tunnel *tunnel = netdev_priv(dev);
  	struct iphdr *iph = &tunnel->parms.iph;
1c213bd24   WANG Cong   net: introduce ne...
1120
  	int err;
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1121

cf124db56   David S. Miller   net: Fix inconsis...
1122
1123
  	dev->needs_free_netdev = true;
  	dev->priv_destructor = ip_tunnel_dev_free;
1c213bd24   WANG Cong   net: introduce ne...
1124
  	dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1125
1126
  	if (!dev->tstats)
  		return -ENOMEM;
e09acddf8   Paolo Abeni   ip_tunnel: replac...
1127
1128
  	err = dst_cache_init(&tunnel->dst_cache, GFP_KERNEL);
  	if (err) {
9a4aa9af4   Tom Herbert   ipv4: Use percpu ...
1129
  		free_percpu(dev->tstats);
e09acddf8   Paolo Abeni   ip_tunnel: replac...
1130
  		return err;
9a4aa9af4   Tom Herbert   ipv4: Use percpu ...
1131
  	}
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1132
1133
  	err = gro_cells_init(&tunnel->gro_cells, dev);
  	if (err) {
e09acddf8   Paolo Abeni   ip_tunnel: replac...
1134
  		dst_cache_destroy(&tunnel->dst_cache);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1135
1136
1137
1138
1139
  		free_percpu(dev->tstats);
  		return err;
  	}
  
  	tunnel->dev = dev;
6c742e714   Nicolas Dichtel   ipip: add x-netns...
1140
  	tunnel->net = dev_net(dev);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1141
1142
1143
  	strcpy(tunnel->parms.name, dev->name);
  	iph->version		= 4;
  	iph->ihl		= 5;
2e15ea390   Pravin B Shelar   ip_gre: Add suppo...
1144
1145
1146
1147
  	if (tunnel->collect_md) {
  		dev->features |= NETIF_F_NETNS_LOCAL;
  		netif_keep_dst(dev);
  	}
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1148
1149
1150
1151
1152
1153
  	return 0;
  }
  EXPORT_SYMBOL_GPL(ip_tunnel_init);
  
  void ip_tunnel_uninit(struct net_device *dev)
  {
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1154
  	struct ip_tunnel *tunnel = netdev_priv(dev);
6c742e714   Nicolas Dichtel   ipip: add x-netns...
1155
  	struct net *net = tunnel->net;
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1156
1157
1158
1159
1160
  	struct ip_tunnel_net *itn;
  
  	itn = net_generic(net, tunnel->ip_tnl_net_id);
  	/* fb_tunnel_dev will be unregisted in net-exit call. */
  	if (itn->fb_tunnel_dev != dev)
2e15ea390   Pravin B Shelar   ip_gre: Add suppo...
1161
  		ip_tunnel_del(itn, netdev_priv(dev));
7d442fab0   Tom Herbert   ipv4: Cache dst i...
1162

e09acddf8   Paolo Abeni   ip_tunnel: replac...
1163
  	dst_cache_reset(&tunnel->dst_cache);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1164
1165
1166
1167
  }
  EXPORT_SYMBOL_GPL(ip_tunnel_uninit);
  
  /* Do least required initialization, rest of init is done in tunnel_init call */
c7d03a00b   Alexey Dobriyan   netns: make struc...
1168
  void ip_tunnel_setup(struct net_device *dev, unsigned int net_id)
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1169
1170
1171
1172
1173
1174
1175
  {
  	struct ip_tunnel *tunnel = netdev_priv(dev);
  	tunnel->ip_tnl_net_id = net_id;
  }
  EXPORT_SYMBOL_GPL(ip_tunnel_setup);
  
  MODULE_LICENSE("GPL");