Blame view

net/ipv4/ip_tunnel.c 29.6 KB
c94229992   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
c54419321   Pravin B Shelar   GRE: Refactor GRE...
2
3
  /*
   * Copyright (c) 2013 Nicira, Inc.
c54419321   Pravin B Shelar   GRE: Refactor GRE...
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
   */
  
  #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...
20
21
22
23
24
25
26
27
28
  #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...
29
  #include <linux/err.h>
c54419321   Pravin B Shelar   GRE: Refactor GRE...
30
31
32
33
34
35
36
37
38
39
40
41
42
43
  
  #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...
44
  #include <net/udp.h>
cfc7381b3   Alexei Starovoitov   ip_tunnel: add co...
45
  #include <net/dst_metadata.h>
63487babf   Tom Herbert   net: Move fou_bui...
46

c54419321   Pravin B Shelar   GRE: Refactor GRE...
47
48
49
50
51
  #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 ...
52
  static unsigned int ip_tunnel_hash(__be32 key, __be32 remote)
c54419321   Pravin B Shelar   GRE: Refactor GRE...
53
54
55
56
  {
  	return hash_32((__force u32)key ^ (__force u32)remote,
  			 IP_TNL_HASH_BITS);
  }
c54419321   Pravin B Shelar   GRE: Refactor GRE...
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
  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 ...
89
  	hash = ip_tunnel_hash(key, remote);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
  	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...
109
  		    t->parms.iph.saddr != 0 ||
c54419321   Pravin B Shelar   GRE: Refactor GRE...
110
111
112
113
114
115
116
117
118
119
120
  		    !(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 ...
121
  	hash = ip_tunnel_hash(key, 0);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
122
123
124
  	head = &itn->tunnels[hash];
  
  	hlist_for_each_entry_rcu(t, head, hash_node) {
e0056593b   Dmitry Popov   ip_tunnel: fix ip...
125
126
127
128
129
  		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...
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
  			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...
146
147
  		    t->parms.iph.saddr != 0 ||
  		    t->parms.iph.daddr != 0 ||
c54419321   Pravin B Shelar   GRE: Refactor GRE...
148
149
150
151
152
153
154
155
156
157
158
159
  		    !(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...
160
  	t = rcu_dereference(itn->collect_md_tun);
833a8b405   Haishuang Yan   ip_tunnel: fix ip...
161
  	if (t && t->dev->flags & IFF_UP)
2e15ea390   Pravin B Shelar   ip_gre: Add suppo...
162
  		return t;
c54419321   Pravin B Shelar   GRE: Refactor GRE...
163
164
  	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...
165
166
167
168
169
170
171
172
173
  	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...
174
  	__be32 i_key = parms->i_key;
c54419321   Pravin B Shelar   GRE: Refactor GRE...
175
176
177
178
179
  
  	if (parms->iph.daddr && !ipv4_is_multicast(parms->iph.daddr))
  		remote = parms->iph.daddr;
  	else
  		remote = 0;
6d608f06e   Steffen Klassert   ip_tunnel: Make v...
180
181
182
183
  	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...
184
185
186
187
188
189
  	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...
190
191
  	if (t->collect_md)
  		rcu_assign_pointer(itn->collect_md_tun, t);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
192
193
  	hlist_add_head_rcu(&t->hash_node, head);
  }
2e15ea390   Pravin B Shelar   ip_gre: Add suppo...
194
  static void ip_tunnel_del(struct ip_tunnel_net *itn, struct ip_tunnel *t)
c54419321   Pravin B Shelar   GRE: Refactor GRE...
195
  {
2e15ea390   Pravin B Shelar   ip_gre: Add suppo...
196
197
  	if (t->collect_md)
  		rcu_assign_pointer(itn->collect_md_tun, NULL);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
198
199
200
201
202
203
204
205
206
207
  	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_...
208
  	__be16 flags = parms->i_flags;
c54419321   Pravin B Shelar   GRE: Refactor GRE...
209
210
211
212
213
214
215
  	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...
216
  		    link == t->parms.link &&
5ce54af1f   Dmitry Popov   ip_tunnel: fix i_...
217
218
  		    type == t->dev->type &&
  		    ip_tunnel_key_match(&t->parms, flags, key))
c54419321   Pravin B Shelar   GRE: Refactor GRE...
219
220
221
222
223
224
225
226
227
228
229
230
231
  			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];
9cb726a21   Eric Dumazet   ip_tunnel: better...
232
233
234
235
  	err = -E2BIG;
  	if (parms->name[0]) {
  		if (!dev_valid_name(parms->name))
  			goto failed;
c54419321   Pravin B Shelar   GRE: Refactor GRE...
236
  		strlcpy(name, parms->name, IFNAMSIZ);
9cb726a21   Eric Dumazet   ip_tunnel: better...
237
238
  	} else {
  		if (strlen(ops->kind) > (IFNAMSIZ - 3))
c54419321   Pravin B Shelar   GRE: Refactor GRE...
239
  			goto failed;
000ade801   Sultan Alsawaf   ip_tunnel: Fix na...
240
241
  		strcpy(name, ops->kind);
  		strcat(name, "%d");
c54419321   Pravin B Shelar   GRE: Refactor GRE...
242
243
244
  	}
  
  	ASSERT_RTNL();
c835a6773   Tom Gundersen   net: set name_ass...
245
  	dev = alloc_netdev(ops->priv_size, name, NET_NAME_UNKNOWN, ops->setup);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
246
247
248
249
250
251
252
253
254
255
  	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 ...
256
  	tunnel->net = net;
c54419321   Pravin B Shelar   GRE: Refactor GRE...
257
258
259
260
261
262
263
264
265
266
267
268
  
  	err = register_netdevice(dev);
  	if (err)
  		goto failed_free;
  
  	return dev;
  
  failed_free:
  	free_netdev(dev);
  failed:
  	return ERR_PTR(err);
  }
c54419321   Pravin B Shelar   GRE: Refactor GRE...
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
  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;
b0066da52   Petr Machata   ip_tunnel: Rename...
284
285
286
  		ip_tunnel_init_flow(&fl4, iph->protocol, iph->daddr,
  				    iph->saddr, tunnel->parms.o_key,
  				    RT_TOS(iph->tos), tunnel->parms.link,
24ba14406   wenxu   route: Add multip...
287
  				    tunnel->fwmark, 0);
7d442fab0   Tom Herbert   ipv4: Cache dst i...
288
  		rt = ip_route_output_key(tunnel->net, &fl4);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
289
290
291
292
293
294
  		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...
295
296
  
  		dst_cache_reset(&tunnel->dst_cache);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
297
298
299
  	}
  
  	if (!tdev && tunnel->parms.link)
6c742e714   Nicolas Dichtel   ipip: add x-netns...
300
  		tdev = __dev_get_by_index(tunnel->net, tunnel->parms.link);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
301
302
303
  
  	if (tdev) {
  		hlen = tdev->hard_header_len + tdev->needed_headroom;
82612de1c   Nicolas Dichtel   ip_tunnel: restor...
304
  		mtu = min(tdev->mtu, IP_MAX_MTU);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
305
  	}
c54419321   Pravin B Shelar   GRE: Refactor GRE...
306
307
308
  
  	dev->needed_headroom = t_hlen + hlen;
  	mtu -= (dev->hard_header_len + t_hlen);
b5476022b   Eric Dumazet   ipv4: igmp: guard...
309
310
  	if (mtu < IPV4_MIN_MTU)
  		mtu = IPV4_MIN_MTU;
c54419321   Pravin B Shelar   GRE: Refactor GRE...
311
312
313
314
315
316
317
318
  
  	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...
319
  	struct ip_tunnel *nt;
c54419321   Pravin B Shelar   GRE: Refactor GRE...
320
  	struct net_device *dev;
b96f9afee   Jarod Wilson   ipv4/6: use core ...
321
  	int t_hlen;
f6cc9c054   Petr Machata   ip_tunnel: Emit e...
322
323
  	int mtu;
  	int err;
c54419321   Pravin B Shelar   GRE: Refactor GRE...
324

79134e6ce   Eric Dumazet   net: do not creat...
325
  	dev = __ip_tunnel_create(net, itn->rtnl_link_ops, parms);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
326
  	if (IS_ERR(dev))
6dd3c9ec2   Florian Westphal   ip_tunnel: return...
327
  		return ERR_CAST(dev);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
328

f6cc9c054   Petr Machata   ip_tunnel: Emit e...
329
330
331
332
  	mtu = ip_tunnel_bind_dev(dev);
  	err = dev_set_mtu(dev, mtu);
  	if (err)
  		goto err_dev_set_mtu;
c54419321   Pravin B Shelar   GRE: Refactor GRE...
333
334
  
  	nt = netdev_priv(dev);
b96f9afee   Jarod Wilson   ipv4/6: use core ...
335
336
  	t_hlen = nt->hlen + sizeof(struct iphdr);
  	dev->min_mtu = ETH_MIN_MTU;
82612de1c   Nicolas Dichtel   ip_tunnel: restor...
337
  	dev->max_mtu = IP_MAX_MTU - dev->hard_header_len - t_hlen;
c54419321   Pravin B Shelar   GRE: Refactor GRE...
338
339
  	ip_tunnel_add(itn, nt);
  	return nt;
f6cc9c054   Petr Machata   ip_tunnel: Emit e...
340
341
342
343
  
  err_dev_set_mtu:
  	unregister_netdevice(dev);
  	return ERR_PTR(err);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
344
345
346
  }
  
  int ip_tunnel_rcv(struct ip_tunnel *tunnel, struct sk_buff *skb,
2e15ea390   Pravin B Shelar   ip_gre: Add suppo...
347
348
  		  const struct tnl_ptk_info *tpi, struct metadata_dst *tun_dst,
  		  bool log_ecn_error)
c54419321   Pravin B Shelar   GRE: Refactor GRE...
349
  {
8f84985fe   Li RongQing   net: unify the pc...
350
  	struct pcpu_sw_netstats *tstats;
c54419321   Pravin B Shelar   GRE: Refactor GRE...
351
352
  	const struct iphdr *iph = ip_hdr(skb);
  	int err;
c54419321   Pravin B Shelar   GRE: Refactor GRE...
353
354
  #ifdef CONFIG_NET_IPGRE_BROADCAST
  	if (ipv4_is_multicast(iph->daddr)) {
c54419321   Pravin B Shelar   GRE: Refactor GRE...
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
  		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...
376
  	skb_reset_network_header(skb);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
  	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 ...
395
  	skb_scrub_packet(skb, !net_eq(tunnel->net, dev_net(tunnel->dev)));
3d7b46cd2   Pravin B Shelar   ip_tunnel: push g...
396
397
398
399
400
401
  	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...
402

2e15ea390   Pravin B Shelar   ip_gre: Add suppo...
403
404
  	if (tun_dst)
  		skb_dst_set(skb, (struct dst_entry *)tun_dst);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
405
406
407
408
  	gro_cells_receive(&tunnel->gro_cells, skb);
  	return 0;
  
  drop:
469f87e15   Haishuang Yan   ip_tunnel: fix po...
409
410
  	if (tun_dst)
  		dst_release((struct dst_entry *)tun_dst);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
411
412
413
414
  	kfree_skb(skb);
  	return 0;
  }
  EXPORT_SYMBOL_GPL(ip_tunnel_rcv);
a8c5f90fb   Tom Herbert   ip_tunnel: Ops re...
415
416
417
  int ip_tunnel_encap_add_ops(const struct ip_tunnel_encap_ops *ops,
  			    unsigned int num)
  {
bb1553c80   Thomas Graf   ip_tunnel: Add sa...
418
419
  	if (num >= MAX_IPTUN_ENCAP_OPS)
  		return -ERANGE;
a8c5f90fb   Tom Herbert   ip_tunnel: Ops re...
420
421
422
  	return !cmpxchg((const struct ip_tunnel_encap_ops **)
  			&iptun_encaps[num],
  			NULL, ops) ? 0 : -1;
563284865   Tom Herbert   net: Changes to i...
423
  }
a8c5f90fb   Tom Herbert   ip_tunnel: Ops re...
424
425
426
427
428
429
  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...
430
431
  	if (num >= MAX_IPTUN_ENCAP_OPS)
  		return -ERANGE;
a8c5f90fb   Tom Herbert   ip_tunnel: Ops re...
432
433
434
435
436
437
438
439
440
  	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...
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
  
  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...
464
  static int tnl_update_pmtu(struct net_device *dev, struct sk_buff *skb,
fc24f2b20   Timo Teräs   ip_tunnel: fix ip...
465
  			    struct rtable *rt, __be16 df,
c8b34e680   wenxu   ip_tunnel: Add tn...
466
467
  			    const struct iphdr *inner_iph,
  			    int tunnel_hlen, __be32 dst, bool md)
23a3647bc   Pravin B Shelar   ip_tunnels: Use s...
468
469
  {
  	struct ip_tunnel *tunnel = netdev_priv(dev);
c8b34e680   wenxu   ip_tunnel: Add tn...
470
  	int pkt_size;
23a3647bc   Pravin B Shelar   ip_tunnels: Use s...
471
  	int mtu;
c8b34e680   wenxu   ip_tunnel: Add tn...
472
473
  	tunnel_hlen = md ? tunnel_hlen : tunnel->hlen;
  	pkt_size = skb->len - tunnel_hlen - dev->hard_header_len;
23a3647bc   Pravin B Shelar   ip_tunnels: Use s...
474
475
  	if (df)
  		mtu = dst_mtu(&rt->dst) - dev->hard_header_len
c8b34e680   wenxu   ip_tunnel: Add tn...
476
  					- sizeof(struct iphdr) - tunnel_hlen;
23a3647bc   Pravin B Shelar   ip_tunnels: Use s...
477
  	else
f4b3ec4e6   Alan Maguire   iptunnel: NULL po...
478
  		mtu = skb_valid_dst(skb) ? dst_mtu(skb_dst(skb)) : dev->mtu;
23a3647bc   Pravin B Shelar   ip_tunnels: Use s...
479

f4b3ec4e6   Alan Maguire   iptunnel: NULL po...
480
481
  	if (skb_valid_dst(skb))
  		skb_dst_update_pmtu(skb, mtu);
23a3647bc   Pravin B Shelar   ip_tunnels: Use s...
482
483
484
  
  	if (skb->protocol == htons(ETH_P_IP)) {
  		if (!skb_is_gso(skb) &&
fc24f2b20   Timo Teräs   ip_tunnel: fix ip...
485
486
  		    (inner_iph->frag_off & htons(IP_DF)) &&
  		    mtu < pkt_size) {
23a3647bc   Pravin B Shelar   ip_tunnels: Use s...
487
488
489
490
491
492
493
  			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)) {
f4b3ec4e6   Alan Maguire   iptunnel: NULL po...
494
  		struct rt6_info *rt6;
c8b34e680   wenxu   ip_tunnel: Add tn...
495
  		__be32 daddr;
f4b3ec4e6   Alan Maguire   iptunnel: NULL po...
496
497
  		rt6 = skb_valid_dst(skb) ? (struct rt6_info *)skb_dst(skb) :
  					   NULL;
c8b34e680   wenxu   ip_tunnel: Add tn...
498
  		daddr = md ? dst : tunnel->parms.iph.daddr;
23a3647bc   Pravin B Shelar   ip_tunnels: Use s...
499
500
501
  
  		if (rt6 && mtu < dst_mtu(skb_dst(skb)) &&
  			   mtu >= IPV6_MIN_MTU) {
c8b34e680   wenxu   ip_tunnel: Add tn...
502
  			if ((daddr && !ipv4_is_multicast(daddr)) ||
23a3647bc   Pravin B Shelar   ip_tunnels: Use s...
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
  			    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;
  }
c8b34e680   wenxu   ip_tunnel: Add tn...
518
519
  void ip_md_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
  		       u8 proto, int tunnel_hlen)
cfc7381b3   Alexei Starovoitov   ip_tunnel: add co...
520
521
522
523
524
525
  {
  	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;
f46fe4f8d   wenxu   ip_tunnel: Add ip...
526
  	struct rtable *rt = NULL;
cfc7381b3   Alexei Starovoitov   ip_tunnel: add co...
527
528
529
  	struct flowi4 fl4;
  	__be16 df = 0;
  	u8 tos, ttl;
f46fe4f8d   wenxu   ip_tunnel: Add ip...
530
  	bool use_cache;
cfc7381b3   Alexei Starovoitov   ip_tunnel: add co...
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
  
  	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);
  	}
6e6b904ad   wenxu   ip_tunnel: Fix ro...
546
547
  	ip_tunnel_init_flow(&fl4, proto, key->u.ipv4.dst, key->u.ipv4.src,
  			    tunnel_id_to_key32(key->tun_id), RT_TOS(tos),
24ba14406   wenxu   route: Add multip...
548
  			    0, skb->mark, skb_get_hash(skb));
cfc7381b3   Alexei Starovoitov   ip_tunnel: add co...
549
550
  	if (tunnel->encap.type != TUNNEL_ENCAP_NONE)
  		goto tx_error;
f46fe4f8d   wenxu   ip_tunnel: Add ip...
551
552
553
554
555
556
557
558
559
560
561
562
563
  
  	use_cache = ip_tunnel_dst_cache_usable(skb, tun_info);
  	if (use_cache)
  		rt = dst_cache_get_ip4(&tun_info->dst_cache, &fl4.saddr);
  	if (!rt) {
  		rt = ip_route_output_key(tunnel->net, &fl4);
  		if (IS_ERR(rt)) {
  			dev->stats.tx_carrier_errors++;
  			goto tx_error;
  		}
  		if (use_cache)
  			dst_cache_set_ip4(&tun_info->dst_cache, &rt->dst,
  					  fl4.saddr);
cfc7381b3   Alexei Starovoitov   ip_tunnel: add co...
564
565
566
567
568
569
  	}
  	if (rt->dst.dev == dev) {
  		ip_rt_put(rt);
  		dev->stats.collisions++;
  		goto tx_error;
  	}
c8b34e680   wenxu   ip_tunnel: Add tn...
570
571
572
573
574
575
576
577
  
  	if (key->tun_flags & TUNNEL_DONT_FRAGMENT)
  		df = htons(IP_DF);
  	if (tnl_update_pmtu(dev, skb, rt, df, inner_iph, tunnel_hlen,
  			    key->u.ipv4.dst, true)) {
  		ip_rt_put(rt);
  		goto tx_error;
  	}
cfc7381b3   Alexei Starovoitov   ip_tunnel: add co...
578
579
580
581
582
583
584
585
586
587
  	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);
  	}
c8b34e680   wenxu   ip_tunnel: Add tn...
588
589
  
  	if (!df && skb->protocol == htons(ETH_P_IP))
cfc7381b3   Alexei Starovoitov   ip_tunnel: add co...
590
  		df = inner_iph->frag_off & htons(IP_DF);
c8b34e680   wenxu   ip_tunnel: Add tn...
591

cfc7381b3   Alexei Starovoitov   ip_tunnel: add co...
592
593
594
595
596
597
598
599
  	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...
600
601
  	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...
602
603
604
605
606
607
608
609
610
611
  	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...
612
  void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
563284865   Tom Herbert   net: Changes to i...
613
  		    const struct iphdr *tnl_params, u8 protocol)
c54419321   Pravin B Shelar   GRE: Refactor GRE...
614
615
  {
  	struct ip_tunnel *tunnel = netdev_priv(dev);
186d93669   wenxu   ip_tunnel: Add ip...
616
  	struct ip_tunnel_info *tun_info = NULL;
c54419321   Pravin B Shelar   GRE: Refactor GRE...
617
  	const struct iphdr *inner_iph;
c54419321   Pravin B Shelar   GRE: Refactor GRE...
618
  	unsigned int max_headroom;	/* The extra header space needed */
186d93669   wenxu   ip_tunnel: Add ip...
619
620
621
622
  	struct rtable *rt = NULL;		/* Route to the other host */
  	bool use_cache = false;
  	struct flowi4 fl4;
  	bool md = false;
22fb22eae   Timo Teräs   ipv4: ip_tunnels:...
623
  	bool connected;
186d93669   wenxu   ip_tunnel: Add ip...
624
625
626
  	u8 tos, ttl;
  	__be32 dst;
  	__be16 df;
c54419321   Pravin B Shelar   GRE: Refactor GRE...
627
628
  
  	inner_iph = (const struct iphdr *)skb_inner_network_header(skb);
22fb22eae   Timo Teräs   ipv4: ip_tunnels:...
629
  	connected = (tunnel->parms.iph.daddr != 0);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
630

5146d1f15   Bernie Harris   tunnel: Clear IPC...
631
  	memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
c54419321   Pravin B Shelar   GRE: Refactor GRE...
632
633
634
  	dst = tnl_params->daddr;
  	if (dst == 0) {
  		/* NBMA tunnel */
51456b291   Ian Morris   ipv4: coding styl...
635
  		if (!skb_dst(skb)) {
c54419321   Pravin B Shelar   GRE: Refactor GRE...
636
637
638
  			dev->stats.tx_fifo_errors++;
  			goto tx_error;
  		}
d71b57532   wenxu   ip_tunnel: Make n...
639
640
641
  		tun_info = skb_tunnel_info(skb);
  		if (tun_info && (tun_info->mode & IP_TUNNEL_INFO_TX) &&
  		    ip_tunnel_info_af(tun_info) == AF_INET &&
186d93669   wenxu   ip_tunnel: Add ip...
642
  		    tun_info->key.u.ipv4.dst) {
d71b57532   wenxu   ip_tunnel: Make n...
643
  			dst = tun_info->key.u.ipv4.dst;
186d93669   wenxu   ip_tunnel: Add ip...
644
645
646
  			md = true;
  			connected = true;
  		}
d71b57532   wenxu   ip_tunnel: Make n...
647
  		else if (skb->protocol == htons(ETH_P_IP)) {
c54419321   Pravin B Shelar   GRE: Refactor GRE...
648
649
650
651
652
653
654
655
656
657
658
659
  			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...
660
  			if (!neigh)
c54419321   Pravin B Shelar   GRE: Refactor GRE...
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
  				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...
684

186d93669   wenxu   ip_tunnel: Add ip...
685
686
  		if (!md)
  			connected = false;
c54419321   Pravin B Shelar   GRE: Refactor GRE...
687
688
689
690
691
  	}
  
  	tos = tnl_params->tos;
  	if (tos & 0x1) {
  		tos &= ~0x1;
7d442fab0   Tom Herbert   ipv4: Cache dst i...
692
  		if (skb->protocol == htons(ETH_P_IP)) {
c54419321   Pravin B Shelar   GRE: Refactor GRE...
693
  			tos = inner_iph->tos;
7d442fab0   Tom Herbert   ipv4: Cache dst i...
694
695
  			connected = false;
  		} else if (skb->protocol == htons(ETH_P_IPV6)) {
c54419321   Pravin B Shelar   GRE: Refactor GRE...
696
  			tos = ipv6_get_dsfield((const struct ipv6hdr *)inner_iph);
7d442fab0   Tom Herbert   ipv4: Cache dst i...
697
698
  			connected = false;
  		}
c54419321   Pravin B Shelar   GRE: Refactor GRE...
699
  	}
0f3e9c97e   David S. Miller   Merge git://git.k...
700
701
  	ip_tunnel_init_flow(&fl4, protocol, dst, tnl_params->saddr,
  			    tunnel->parms.o_key, RT_TOS(tos), tunnel->parms.link,
24ba14406   wenxu   route: Add multip...
702
  			    tunnel->fwmark, skb_get_hash(skb));
7d442fab0   Tom Herbert   ipv4: Cache dst i...
703

563284865   Tom Herbert   net: Changes to i...
704
705
  	if (ip_tunnel_encap(skb, tunnel, &protocol, &fl4) < 0)
  		goto tx_error;
186d93669   wenxu   ip_tunnel: Add ip...
706
707
708
709
710
711
712
713
714
  	if (connected && md) {
  		use_cache = ip_tunnel_dst_cache_usable(skb, tun_info);
  		if (use_cache)
  			rt = dst_cache_get_ip4(&tun_info->dst_cache,
  					       &fl4.saddr);
  	} else {
  		rt = connected ? dst_cache_get_ip4(&tunnel->dst_cache,
  						&fl4.saddr) : NULL;
  	}
7d442fab0   Tom Herbert   ipv4: Cache dst i...
715
716
717
718
719
720
721
722
  
  	if (!rt) {
  		rt = ip_route_output_key(tunnel->net, &fl4);
  
  		if (IS_ERR(rt)) {
  			dev->stats.tx_carrier_errors++;
  			goto tx_error;
  		}
186d93669   wenxu   ip_tunnel: Add ip...
723
724
725
726
  		if (use_cache)
  			dst_cache_set_ip4(&tun_info->dst_cache, &rt->dst,
  					  fl4.saddr);
  		else if (!md && connected)
e09acddf8   Paolo Abeni   ip_tunnel: replac...
727
728
  			dst_cache_set_ip4(&tunnel->dst_cache, &rt->dst,
  					  fl4.saddr);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
729
  	}
7d442fab0   Tom Herbert   ipv4: Cache dst i...
730

0e6fbc5b6   Pravin B Shelar   ip_tunnels: exten...
731
  	if (rt->dst.dev == dev) {
c54419321   Pravin B Shelar   GRE: Refactor GRE...
732
733
734
735
  		ip_rt_put(rt);
  		dev->stats.collisions++;
  		goto tx_error;
  	}
c54419321   Pravin B Shelar   GRE: Refactor GRE...
736

c8b34e680   wenxu   ip_tunnel: Add tn...
737
738
  	if (tnl_update_pmtu(dev, skb, rt, tnl_params->frag_off, inner_iph,
  			    0, 0, false)) {
23a3647bc   Pravin B Shelar   ip_tunnels: Use s...
739
740
  		ip_rt_put(rt);
  		goto tx_error;
c54419321   Pravin B Shelar   GRE: Refactor GRE...
741
  	}
c54419321   Pravin B Shelar   GRE: Refactor GRE...
742
743
744
745
746
747
748
749
750
751
  
  	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...
752
  	tos = ip_tunnel_ecn_encap(tos, inner_iph, skb);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
753
754
755
756
757
758
759
760
761
762
763
  	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...
764
  	df = tnl_params->frag_off;
22a59be8b   Philip Prindeville   net: ipv4: Add ab...
765
  	if (skb->protocol == htons(ETH_P_IP) && !tunnel->ignore_df)
23a3647bc   Pravin B Shelar   ip_tunnels: Use s...
766
  		df |= (inner_iph->frag_off&htons(IP_DF));
0e6fbc5b6   Pravin B Shelar   ip_tunnels: exten...
767
  	max_headroom = LL_RESERVED_SPACE(rt->dst.dev) + sizeof(struct iphdr)
7371e0221   Tom Herbert   ip_tunnel: Accoun...
768
  			+ rt->dst.header_len + ip_encap_hlen(&tunnel->encap);
3e08f4a72   Steffen Klassert   ip_tunnel: Fix a ...
769
  	if (max_headroom > dev->needed_headroom)
c54419321   Pravin B Shelar   GRE: Refactor GRE...
770
  		dev->needed_headroom = max_headroom;
3e08f4a72   Steffen Klassert   ip_tunnel: Fix a ...
771
772
  
  	if (skb_cow_head(skb, dev->needed_headroom)) {
586d5fc86   Dmitry Popov   ip_tunnel: fix po...
773
  		ip_rt_put(rt);
3e08f4a72   Steffen Klassert   ip_tunnel: Fix a ...
774
  		dev->stats.tx_dropped++;
3acfa1e73   Eric Dumazet   ipv4: be friend w...
775
  		kfree_skb(skb);
3e08f4a72   Steffen Klassert   ip_tunnel: Fix a ...
776
  		return;
c54419321   Pravin B Shelar   GRE: Refactor GRE...
777
  	}
039f50629   Pravin B Shelar   ip_tunnel: Move s...
778
779
  	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...
780
781
782
783
784
785
786
787
  	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...
788
  	kfree_skb(skb);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
789
790
791
792
793
794
795
  }
  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 ...
796
797
  			     bool set_mtu,
  			     __u32 fwmark)
c54419321   Pravin B Shelar   GRE: Refactor GRE...
798
  {
2e15ea390   Pravin B Shelar   ip_gre: Add suppo...
799
  	ip_tunnel_del(itn, t);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
800
801
802
803
804
805
806
807
808
809
810
811
812
  	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 ...
813
  	if (t->parms.link != p->link || t->fwmark != fwmark) {
c54419321   Pravin B Shelar   GRE: Refactor GRE...
814
815
816
  		int mtu;
  
  		t->parms.link = p->link;
9830ad4c6   Craig Gallek   ip_tunnel: Allow ...
817
  		t->fwmark = fwmark;
c54419321   Pravin B Shelar   GRE: Refactor GRE...
818
819
820
821
  		mtu = ip_tunnel_bind_dev(dev);
  		if (set_mtu)
  			dev->mtu = mtu;
  	}
e09acddf8   Paolo Abeni   ip_tunnel: replac...
822
  	dst_cache_reset(&t->dst_cache);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
823
824
825
826
827
828
  	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...
829
830
831
  	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...
832

c54419321   Pravin B Shelar   GRE: Refactor GRE...
833
834
  	switch (cmd) {
  	case SIOCGETTUNNEL:
8c923ce21   Nicolas Dichtel   ip_tunnel: use th...
835
  		if (dev == itn->fb_tunnel_dev) {
c54419321   Pravin B Shelar   GRE: Refactor GRE...
836
  			t = ip_tunnel_find(itn, p, itn->fb_tunnel_dev->type);
51456b291   Ian Morris   ipv4: coding styl...
837
  			if (!t)
8c923ce21   Nicolas Dichtel   ip_tunnel: use th...
838
839
  				t = netdev_priv(dev);
  		}
c54419321   Pravin B Shelar   GRE: Refactor GRE...
840
841
842
843
844
845
846
847
848
849
  		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...
850
851
852
853
854
855
  		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...
856

79134e6ce   Eric Dumazet   net: do not creat...
857
  		t = ip_tunnel_find(itn, p, itn->type);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
858

d61746b2e   Steffen Klassert   ip_tunnel: Don't ...
859
860
861
862
863
864
865
866
  		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 ...
867
  			break;
6dd3c9ec2   Florian Westphal   ip_tunnel: return...
868
  		}
c54419321   Pravin B Shelar   GRE: Refactor GRE...
869
  		if (dev != itn->fb_tunnel_dev && cmd == SIOCCHGTUNNEL) {
00db41243   Ian Morris   ipv4: coding styl...
870
  			if (t) {
c54419321   Pravin B Shelar   GRE: Refactor GRE...
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
  				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 ...
894
  			ip_tunnel_update(itn, t, dev, p, true, 0);
6dd3c9ec2   Florian Westphal   ip_tunnel: return...
895
896
897
  		} else {
  			err = -ENOENT;
  		}
c54419321   Pravin B Shelar   GRE: Refactor GRE...
898
899
900
901
902
903
904
905
906
907
  		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...
908
  			if (!t)
c54419321   Pravin B Shelar   GRE: Refactor GRE...
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
  				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...
927
  int __ip_tunnel_change_mtu(struct net_device *dev, int new_mtu, bool strict)
c54419321   Pravin B Shelar   GRE: Refactor GRE...
928
929
930
  {
  	struct ip_tunnel *tunnel = netdev_priv(dev);
  	int t_hlen = tunnel->hlen + sizeof(struct iphdr);
82612de1c   Nicolas Dichtel   ip_tunnel: restor...
931
  	int max_mtu = IP_MAX_MTU - dev->hard_header_len - t_hlen;
c54419321   Pravin B Shelar   GRE: Refactor GRE...
932

b96f9afee   Jarod Wilson   ipv4/6: use core ...
933
  	if (new_mtu < ETH_MIN_MTU)
c54419321   Pravin B Shelar   GRE: Refactor GRE...
934
  		return -EINVAL;
7e059158d   David Wragg   vxlan, gre, genev...
935
936
937
938
939
940
941
  
  	if (new_mtu > max_mtu) {
  		if (strict)
  			return -EINVAL;
  
  		new_mtu = max_mtu;
  	}
c54419321   Pravin B Shelar   GRE: Refactor GRE...
942
943
944
  	dev->mtu = new_mtu;
  	return 0;
  }
7e059158d   David Wragg   vxlan, gre, genev...
945
946
947
948
949
950
  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...
951
952
953
954
955
956
957
  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...
958
  	dst_cache_destroy(&tunnel->dst_cache);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
959
  	free_percpu(dev->tstats);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
960
961
962
963
  }
  
  void ip_tunnel_dellink(struct net_device *dev, struct list_head *head)
  {
c54419321   Pravin B Shelar   GRE: Refactor GRE...
964
965
  	struct ip_tunnel *tunnel = netdev_priv(dev);
  	struct ip_tunnel_net *itn;
6c742e714   Nicolas Dichtel   ipip: add x-netns...
966
  	itn = net_generic(tunnel->net, tunnel->ip_tnl_net_id);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
967
968
  
  	if (itn->fb_tunnel_dev != dev) {
2e15ea390   Pravin B Shelar   ip_gre: Add suppo...
969
  		ip_tunnel_del(itn, netdev_priv(dev));
c54419321   Pravin B Shelar   GRE: Refactor GRE...
970
971
972
973
  		unregister_netdevice_queue(dev, head);
  	}
  }
  EXPORT_SYMBOL_GPL(ip_tunnel_dellink);
1728d4fab   Nicolas Dichtel   tunnels: advertis...
974
975
976
977
978
979
980
  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:...
981
982
983
984
985
986
987
  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...
988
  int ip_tunnel_init_net(struct net *net, unsigned int ip_tnl_net_id,
c54419321   Pravin B Shelar   GRE: Refactor GRE...
989
990
991
992
  				  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 ...
993
  	unsigned int i;
c54419321   Pravin B Shelar   GRE: Refactor GRE...
994

79134e6ce   Eric Dumazet   net: do not creat...
995
  	itn->rtnl_link_ops = ops;
6261d983f   stephen hemminger   ip_tunnel: embed ...
996
997
  	for (i = 0; i < IP_TNL_HASH_SIZE; i++)
  		INIT_HLIST_HEAD(&itn->tunnels[i]);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
998

79134e6ce   Eric Dumazet   net: do not creat...
999
1000
1001
1002
1003
  	if (!ops || !net_has_fallback_tunnels(net)) {
  		struct ip_tunnel_net *it_init_net;
  
  		it_init_net = net_generic(&init_net, ip_tnl_net_id);
  		itn->type = it_init_net->type;
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1004
1005
1006
  		itn->fb_tunnel_dev = NULL;
  		return 0;
  	}
6261d983f   stephen hemminger   ip_tunnel: embed ...
1007

c54419321   Pravin B Shelar   GRE: Refactor GRE...
1008
1009
1010
1011
1012
1013
  	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...
1014
1015
1016
  	/* 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...
1017
  	if (!IS_ERR(itn->fb_tunnel_dev)) {
b4de77ade   Dan Carpenter   ipip: potential r...
1018
  		itn->fb_tunnel_dev->features |= NETIF_F_NETNS_LOCAL;
78ff4be45   Steffen Klassert   ip_tunnel: Initia...
1019
  		itn->fb_tunnel_dev->mtu = ip_tunnel_bind_dev(itn->fb_tunnel_dev);
670132826   Steffen Klassert   ip_tunnel: Add fa...
1020
  		ip_tunnel_add(itn, netdev_priv(itn->fb_tunnel_dev));
79134e6ce   Eric Dumazet   net: do not creat...
1021
  		itn->type = itn->fb_tunnel_dev->type;
670132826   Steffen Klassert   ip_tunnel: Add fa...
1022
  	}
b4de77ade   Dan Carpenter   ipip: potential r...
1023
  	rtnl_unlock();
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1024

27d79f3b1   Sachin Kamat   net: ipv4: Use PT...
1025
  	return PTR_ERR_OR_ZERO(itn->fb_tunnel_dev);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1026
1027
  }
  EXPORT_SYMBOL_GPL(ip_tunnel_init_net);
79134e6ce   Eric Dumazet   net: do not creat...
1028
1029
  static void ip_tunnel_destroy(struct net *net, struct ip_tunnel_net *itn,
  			      struct list_head *head,
6c742e714   Nicolas Dichtel   ipip: add x-netns...
1030
  			      struct rtnl_link_ops *ops)
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1031
  {
6c742e714   Nicolas Dichtel   ipip: add x-netns...
1032
  	struct net_device *dev, *aux;
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1033
  	int h;
6c742e714   Nicolas Dichtel   ipip: add x-netns...
1034
1035
1036
  	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...
1037
1038
1039
1040
1041
1042
  	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...
1043
1044
1045
1046
1047
  			/* 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...
1048
  	}
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1049
  }
64bc17811   Eric Dumazet   ipv4: speedup ipv...
1050
1051
  void ip_tunnel_delete_nets(struct list_head *net_list, unsigned int id,
  			   struct rtnl_link_ops *ops)
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1052
  {
64bc17811   Eric Dumazet   ipv4: speedup ipv...
1053
1054
  	struct ip_tunnel_net *itn;
  	struct net *net;
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1055
1056
1057
  	LIST_HEAD(list);
  
  	rtnl_lock();
64bc17811   Eric Dumazet   ipv4: speedup ipv...
1058
1059
  	list_for_each_entry(net, net_list, exit_list) {
  		itn = net_generic(net, id);
79134e6ce   Eric Dumazet   net: do not creat...
1060
  		ip_tunnel_destroy(net, itn, &list, ops);
64bc17811   Eric Dumazet   ipv4: speedup ipv...
1061
  	}
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1062
1063
  	unregister_netdevice_many(&list);
  	rtnl_unlock();
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1064
  }
64bc17811   Eric Dumazet   ipv4: speedup ipv...
1065
  EXPORT_SYMBOL_GPL(ip_tunnel_delete_nets);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1066
1067
  
  int ip_tunnel_newlink(struct net_device *dev, struct nlattr *tb[],
9830ad4c6   Craig Gallek   ip_tunnel: Allow ...
1068
  		      struct ip_tunnel_parm *p, __u32 fwmark)
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1069
1070
1071
1072
1073
1074
1075
1076
1077
  {
  	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...
1078
1079
1080
1081
1082
1083
1084
  	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...
1085

5e6700b3b   Nicolas Dichtel   sit: add support ...
1086
  	nt->net = net;
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1087
  	nt->parms = *p;
9830ad4c6   Craig Gallek   ip_tunnel: Allow ...
1088
  	nt->fwmark = fwmark;
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1089
1090
  	err = register_netdevice(dev);
  	if (err)
f6cc9c054   Petr Machata   ip_tunnel: Emit e...
1091
  		goto err_register_netdevice;
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1092
1093
1094
1095
1096
  
  	if (dev->type == ARPHRD_ETHER && !tb[IFLA_ADDRESS])
  		eth_hw_addr_random(dev);
  
  	mtu = ip_tunnel_bind_dev(dev);
24fc79798   Stefano Brivio   ip_tunnel: Clamp ...
1097
  	if (tb[IFLA_MTU]) {
82612de1c   Nicolas Dichtel   ip_tunnel: restor...
1098
  		unsigned int max = IP_MAX_MTU - dev->hard_header_len - nt->hlen;
24fc79798   Stefano Brivio   ip_tunnel: Clamp ...
1099

5568cdc36   David S. Miller   ip_tunnel: Resolv...
1100
1101
  		mtu = clamp(dev->mtu, (unsigned int)ETH_MIN_MTU,
  			    (unsigned int)(max - sizeof(struct iphdr)));
f6cc9c054   Petr Machata   ip_tunnel: Emit e...
1102
  	}
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1103

5568cdc36   David S. Miller   ip_tunnel: Resolv...
1104
1105
1106
  	err = dev_set_mtu(dev, mtu);
  	if (err)
  		goto err_dev_set_mtu;
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1107
1108
  
  	ip_tunnel_add(itn, nt);
f6cc9c054   Petr Machata   ip_tunnel: Emit e...
1109
1110
1111
1112
1113
  	return 0;
  
  err_dev_set_mtu:
  	unregister_netdevice(dev);
  err_register_netdevice:
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1114
1115
1116
1117
1118
  	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 ...
1119
  			 struct ip_tunnel_parm *p, __u32 fwmark)
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1120
  {
6c742e714   Nicolas Dichtel   ipip: add x-netns...
1121
  	struct ip_tunnel *t;
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1122
  	struct ip_tunnel *tunnel = netdev_priv(dev);
6c742e714   Nicolas Dichtel   ipip: add x-netns...
1123
  	struct net *net = tunnel->net;
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1124
1125
1126
1127
  	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...
1128
1129
1130
1131
1132
1133
  	t = ip_tunnel_find(itn, p, dev->type);
  
  	if (t) {
  		if (t->dev != dev)
  			return -EEXIST;
  	} else {
6c742e714   Nicolas Dichtel   ipip: add x-netns...
1134
  		t = tunnel;
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
  
  		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 ...
1149
  	ip_tunnel_update(itn, t, dev, p, !tb[IFLA_MTU], fwmark);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1150
1151
1152
1153
1154
1155
1156
1157
  	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...
1158
  	int err;
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1159

cf124db56   David S. Miller   net: Fix inconsis...
1160
1161
  	dev->needs_free_netdev = true;
  	dev->priv_destructor = ip_tunnel_dev_free;
1c213bd24   WANG Cong   net: introduce ne...
1162
  	dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1163
1164
  	if (!dev->tstats)
  		return -ENOMEM;
e09acddf8   Paolo Abeni   ip_tunnel: replac...
1165
1166
  	err = dst_cache_init(&tunnel->dst_cache, GFP_KERNEL);
  	if (err) {
9a4aa9af4   Tom Herbert   ipv4: Use percpu ...
1167
  		free_percpu(dev->tstats);
e09acddf8   Paolo Abeni   ip_tunnel: replac...
1168
  		return err;
9a4aa9af4   Tom Herbert   ipv4: Use percpu ...
1169
  	}
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1170
1171
  	err = gro_cells_init(&tunnel->gro_cells, dev);
  	if (err) {
e09acddf8   Paolo Abeni   ip_tunnel: replac...
1172
  		dst_cache_destroy(&tunnel->dst_cache);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1173
1174
1175
1176
1177
  		free_percpu(dev->tstats);
  		return err;
  	}
  
  	tunnel->dev = dev;
6c742e714   Nicolas Dichtel   ipip: add x-netns...
1178
  	tunnel->net = dev_net(dev);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1179
1180
1181
  	strcpy(tunnel->parms.name, dev->name);
  	iph->version		= 4;
  	iph->ihl		= 5;
2e15ea390   Pravin B Shelar   ip_gre: Add suppo...
1182
1183
1184
1185
  	if (tunnel->collect_md) {
  		dev->features |= NETIF_F_NETNS_LOCAL;
  		netif_keep_dst(dev);
  	}
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1186
1187
1188
1189
1190
1191
  	return 0;
  }
  EXPORT_SYMBOL_GPL(ip_tunnel_init);
  
  void ip_tunnel_uninit(struct net_device *dev)
  {
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1192
  	struct ip_tunnel *tunnel = netdev_priv(dev);
6c742e714   Nicolas Dichtel   ipip: add x-netns...
1193
  	struct net *net = tunnel->net;
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1194
1195
1196
1197
1198
  	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...
1199
  		ip_tunnel_del(itn, netdev_priv(dev));
7d442fab0   Tom Herbert   ipv4: Cache dst i...
1200

e09acddf8   Paolo Abeni   ip_tunnel: replac...
1201
  	dst_cache_reset(&tunnel->dst_cache);
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1202
1203
1204
1205
  }
  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...
1206
  void ip_tunnel_setup(struct net_device *dev, unsigned int net_id)
c54419321   Pravin B Shelar   GRE: Refactor GRE...
1207
1208
1209
1210
1211
1212
1213
  {
  	struct ip_tunnel *tunnel = netdev_priv(dev);
  	tunnel->ip_tnl_net_id = net_id;
  }
  EXPORT_SYMBOL_GPL(ip_tunnel_setup);
  
  MODULE_LICENSE("GPL");