Blame view

net/ipv6/ip6_vti.c 31.4 KB
2874c5fd2   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
ed1efb2ae   Steffen Klassert   ipv6: Add support...
2
3
4
5
6
7
8
9
10
11
  /*
   *	IPv6 virtual tunneling interface
   *
   *	Copyright (C) 2013 secunet Security Networks AG
   *
   *	Author:
   *	Steffen Klassert <steffen.klassert@secunet.com>
   *
   *	Based on:
   *	net/ipv6/ip6_tunnel.c
ed1efb2ae   Steffen Klassert   ipv6: Add support...
12
13
14
15
16
17
18
19
20
21
22
   */
  
  #include <linux/module.h>
  #include <linux/capability.h>
  #include <linux/errno.h>
  #include <linux/types.h>
  #include <linux/sockios.h>
  #include <linux/icmp.h>
  #include <linux/if.h>
  #include <linux/in.h>
  #include <linux/ip.h>
ed1efb2ae   Steffen Klassert   ipv6: Add support...
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
  #include <linux/net.h>
  #include <linux/in6.h>
  #include <linux/netdevice.h>
  #include <linux/if_arp.h>
  #include <linux/icmpv6.h>
  #include <linux/init.h>
  #include <linux/route.h>
  #include <linux/rtnetlink.h>
  #include <linux/netfilter_ipv6.h>
  #include <linux/slab.h>
  #include <linux/hash.h>
  
  #include <linux/uaccess.h>
  #include <linux/atomic.h>
  
  #include <net/icmp.h>
  #include <net/ip.h>
  #include <net/ip_tunnels.h>
  #include <net/ipv6.h>
  #include <net/ip6_route.h>
  #include <net/addrconf.h>
  #include <net/ip6_tunnel.h>
  #include <net/xfrm.h>
  #include <net/net_namespace.h>
  #include <net/netns/generic.h>
45ce0fd19   Felix Jia   net/ipv6: support...
48
  #include <linux/etherdevice.h>
ed1efb2ae   Steffen Klassert   ipv6: Add support...
49

e87a8f24c   Jiri Kosina   net: resolve symb...
50
51
  #define IP6_VTI_HASH_SIZE_SHIFT  5
  #define IP6_VTI_HASH_SIZE (1 << IP6_VTI_HASH_SIZE_SHIFT)
ed1efb2ae   Steffen Klassert   ipv6: Add support...
52
53
54
55
  
  static u32 HASH(const struct in6_addr *addr1, const struct in6_addr *addr2)
  {
  	u32 hash = ipv6_addr_hash(addr1) ^ ipv6_addr_hash(addr2);
e87a8f24c   Jiri Kosina   net: resolve symb...
56
  	return hash_32(hash, IP6_VTI_HASH_SIZE_SHIFT);
ed1efb2ae   Steffen Klassert   ipv6: Add support...
57
58
59
60
61
  }
  
  static int vti6_dev_init(struct net_device *dev);
  static void vti6_dev_setup(struct net_device *dev);
  static struct rtnl_link_ops vti6_link_ops __read_mostly;
c7d03a00b   Alexey Dobriyan   netns: make struc...
62
  static unsigned int vti6_net_id __read_mostly;
ed1efb2ae   Steffen Klassert   ipv6: Add support...
63
64
65
66
  struct vti6_net {
  	/* the vti6 tunnel fallback device */
  	struct net_device *fb_tnl_dev;
  	/* lists for storing tunnels in use */
e87a8f24c   Jiri Kosina   net: resolve symb...
67
  	struct ip6_tnl __rcu *tnls_r_l[IP6_VTI_HASH_SIZE];
ed1efb2ae   Steffen Klassert   ipv6: Add support...
68
69
70
  	struct ip6_tnl __rcu *tnls_wc[1];
  	struct ip6_tnl __rcu **tnls[2];
  };
ed1efb2ae   Steffen Klassert   ipv6: Add support...
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
  #define for_each_vti6_tunnel_rcu(start) \
  	for (t = rcu_dereference(start); t; t = rcu_dereference(t->next))
  
  /**
   * vti6_tnl_lookup - fetch tunnel matching the end-point addresses
   *   @net: network namespace
   *   @remote: the address of the tunnel exit-point
   *   @local: the address of the tunnel entry-point
   *
   * Return:
   *   tunnel matching given end-points if found,
   *   else fallback tunnel if its device is up,
   *   else %NULL
   **/
  static struct ip6_tnl *
  vti6_tnl_lookup(struct net *net, const struct in6_addr *remote,
  		const struct in6_addr *local)
  {
  	unsigned int hash = HASH(remote, local);
  	struct ip6_tnl *t;
  	struct vti6_net *ip6n = net_generic(net, vti6_net_id);
fbe68ee87   Steffen Klassert   vti6: Add a looku...
92
  	struct in6_addr any;
ed1efb2ae   Steffen Klassert   ipv6: Add support...
93
94
95
96
97
98
99
  
  	for_each_vti6_tunnel_rcu(ip6n->tnls_r_l[hash]) {
  		if (ipv6_addr_equal(local, &t->parms.laddr) &&
  		    ipv6_addr_equal(remote, &t->parms.raddr) &&
  		    (t->dev->flags & IFF_UP))
  			return t;
  	}
fbe68ee87   Steffen Klassert   vti6: Add a looku...
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
  
  	memset(&any, 0, sizeof(any));
  	hash = HASH(&any, local);
  	for_each_vti6_tunnel_rcu(ip6n->tnls_r_l[hash]) {
  		if (ipv6_addr_equal(local, &t->parms.laddr) &&
  		    (t->dev->flags & IFF_UP))
  			return t;
  	}
  
  	hash = HASH(remote, &any);
  	for_each_vti6_tunnel_rcu(ip6n->tnls_r_l[hash]) {
  		if (ipv6_addr_equal(remote, &t->parms.raddr) &&
  		    (t->dev->flags & IFF_UP))
  			return t;
  	}
ed1efb2ae   Steffen Klassert   ipv6: Add support...
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
  	t = rcu_dereference(ip6n->tnls_wc[0]);
  	if (t && (t->dev->flags & IFF_UP))
  		return t;
  
  	return NULL;
  }
  
  /**
   * vti6_tnl_bucket - get head of list matching given tunnel parameters
   *   @p: parameters containing tunnel end-points
   *
   * Description:
   *   vti6_tnl_bucket() returns the head of the list matching the
   *   &struct in6_addr entries laddr and raddr in @p.
   *
   * Return: head of IPv6 tunnel list
   **/
  static struct ip6_tnl __rcu **
  vti6_tnl_bucket(struct vti6_net *ip6n, const struct __ip6_tnl_parm *p)
  {
  	const struct in6_addr *remote = &p->raddr;
  	const struct in6_addr *local = &p->laddr;
  	unsigned int h = 0;
  	int prio = 0;
  
  	if (!ipv6_addr_any(remote) || !ipv6_addr_any(local)) {
  		prio = 1;
  		h = HASH(remote, local);
  	}
  	return &ip6n->tnls[prio][h];
  }
  
  static void
  vti6_tnl_link(struct vti6_net *ip6n, struct ip6_tnl *t)
  {
  	struct ip6_tnl __rcu **tp = vti6_tnl_bucket(ip6n, &t->parms);
  
  	rcu_assign_pointer(t->next , rtnl_dereference(*tp));
  	rcu_assign_pointer(*tp, t);
  }
  
  static void
  vti6_tnl_unlink(struct vti6_net *ip6n, struct ip6_tnl *t)
  {
  	struct ip6_tnl __rcu **tp;
  	struct ip6_tnl *iter;
  
  	for (tp = vti6_tnl_bucket(ip6n, &t->parms);
  	     (iter = rtnl_dereference(*tp)) != NULL;
  	     tp = &iter->next) {
  		if (t == iter) {
  			rcu_assign_pointer(*tp, t->next);
  			break;
  		}
  	}
  }
  
  static void vti6_dev_free(struct net_device *dev)
  {
  	free_percpu(dev->tstats);
ed1efb2ae   Steffen Klassert   ipv6: Add support...
175
176
177
178
179
180
181
182
  }
  
  static int vti6_tnl_create2(struct net_device *dev)
  {
  	struct ip6_tnl *t = netdev_priv(dev);
  	struct net *net = dev_net(dev);
  	struct vti6_net *ip6n = net_generic(net, vti6_net_id);
  	int err;
93e246f78   David Forster   vti6: fix device ...
183
  	dev->rtnl_link_ops = &vti6_link_ops;
ed1efb2ae   Steffen Klassert   ipv6: Add support...
184
185
186
187
188
  	err = register_netdevice(dev);
  	if (err < 0)
  		goto out;
  
  	strcpy(t->parms.name, dev->name);
ed1efb2ae   Steffen Klassert   ipv6: Add support...
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
  
  	dev_hold(dev);
  	vti6_tnl_link(ip6n, t);
  
  	return 0;
  
  out:
  	return err;
  }
  
  static struct ip6_tnl *vti6_tnl_create(struct net *net, struct __ip6_tnl_parm *p)
  {
  	struct net_device *dev;
  	struct ip6_tnl *t;
  	char name[IFNAMSIZ];
  	int err;
537b361fb   Eric Dumazet   vti6: better vali...
205
206
207
  	if (p->name[0]) {
  		if (!dev_valid_name(p->name))
  			goto failed;
ed1efb2ae   Steffen Klassert   ipv6: Add support...
208
  		strlcpy(name, p->name, IFNAMSIZ);
537b361fb   Eric Dumazet   vti6: better vali...
209
  	} else {
ed1efb2ae   Steffen Klassert   ipv6: Add support...
210
  		sprintf(name, "ip6_vti%%d");
537b361fb   Eric Dumazet   vti6: better vali...
211
  	}
ed1efb2ae   Steffen Klassert   ipv6: Add support...
212

c835a6773   Tom Gundersen   net: set name_ass...
213
  	dev = alloc_netdev(sizeof(*t), name, NET_NAME_UNKNOWN, vti6_dev_setup);
63159f29b   Ian Morris   ipv6: coding styl...
214
  	if (!dev)
ed1efb2ae   Steffen Klassert   ipv6: Add support...
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
  		goto failed;
  
  	dev_net_set(dev, net);
  
  	t = netdev_priv(dev);
  	t->parms = *p;
  	t->net = dev_net(dev);
  
  	err = vti6_tnl_create2(dev);
  	if (err < 0)
  		goto failed_free;
  
  	return t;
  
  failed_free:
cf124db56   David S. Miller   net: Fix inconsis...
230
  	free_netdev(dev);
ed1efb2ae   Steffen Klassert   ipv6: Add support...
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
  failed:
  	return NULL;
  }
  
  /**
   * vti6_locate - find or create tunnel matching given parameters
   *   @net: network namespace
   *   @p: tunnel parameters
   *   @create: != 0 if allowed to create new tunnel if no match found
   *
   * Description:
   *   vti6_locate() first tries to locate an existing tunnel
   *   based on @parms. If this is unsuccessful, but @create is set a new
   *   tunnel device is created and registered for use.
   *
   * Return:
   *   matching tunnel or NULL
   **/
  static struct ip6_tnl *vti6_locate(struct net *net, struct __ip6_tnl_parm *p,
  				   int create)
  {
  	const struct in6_addr *remote = &p->raddr;
  	const struct in6_addr *local = &p->laddr;
  	struct ip6_tnl __rcu **tp;
  	struct ip6_tnl *t;
  	struct vti6_net *ip6n = net_generic(net, vti6_net_id);
  
  	for (tp = vti6_tnl_bucket(ip6n, p);
  	     (t = rtnl_dereference(*tp)) != NULL;
  	     tp = &t->next) {
  		if (ipv6_addr_equal(local, &t->parms.laddr) &&
d814b847b   Steffen Klassert   ip6_vti: Return a...
262
263
264
  		    ipv6_addr_equal(remote, &t->parms.raddr)) {
  			if (create)
  				return NULL;
ed1efb2ae   Steffen Klassert   ipv6: Add support...
265
  			return t;
d814b847b   Steffen Klassert   ip6_vti: Return a...
266
  		}
ed1efb2ae   Steffen Klassert   ipv6: Add support...
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
  	}
  	if (!create)
  		return NULL;
  	return vti6_tnl_create(net, p);
  }
  
  /**
   * vti6_dev_uninit - tunnel device uninitializer
   *   @dev: the device to be destroyed
   *
   * Description:
   *   vti6_dev_uninit() removes tunnel from its list
   **/
  static void vti6_dev_uninit(struct net_device *dev)
  {
  	struct ip6_tnl *t = netdev_priv(dev);
092a29a40   Yao Xiwei   vti6: fix uninit ...
283
  	struct vti6_net *ip6n = net_generic(t->net, vti6_net_id);
ed1efb2ae   Steffen Klassert   ipv6: Add support...
284
285
286
287
288
  
  	if (dev == ip6n->fb_tnl_dev)
  		RCU_INIT_POINTER(ip6n->tnls_wc[0], NULL);
  	else
  		vti6_tnl_unlink(ip6n, t);
ed1efb2ae   Steffen Klassert   ipv6: Add support...
289
290
  	dev_put(dev);
  }
0146dca70   Sabrina Dubroca   xfrm: add support...
291
292
  static int vti6_input_proto(struct sk_buff *skb, int nexthdr, __be32 spi,
  			    int encap_type)
ed1efb2ae   Steffen Klassert   ipv6: Add support...
293
294
295
296
297
  {
  	struct ip6_tnl *t;
  	const struct ipv6hdr *ipv6h = ipv6_hdr(skb);
  
  	rcu_read_lock();
e5d08d718   Ian Morris   ipv6: coding styl...
298
  	t = vti6_tnl_lookup(dev_net(skb->dev), &ipv6h->saddr, &ipv6h->daddr);
53b24b8f9   Ian Morris   ipv6: coding styl...
299
  	if (t) {
ed1efb2ae   Steffen Klassert   ipv6: Add support...
300
301
302
303
304
305
306
  		if (t->parms.proto != IPPROTO_IPV6 && t->parms.proto != 0) {
  			rcu_read_unlock();
  			goto discard;
  		}
  
  		if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
  			rcu_read_unlock();
2a9de3af2   Torsten Hilbrich   vti6: Fix memory ...
307
  			goto discard;
ed1efb2ae   Steffen Klassert   ipv6: Add support...
308
  		}
cbb49697d   Eric Dumazet   ipv6: tunnels: fi...
309
  		ipv6h = ipv6_hdr(skb);
ed1efb2ae   Steffen Klassert   ipv6: Add support...
310
311
312
313
314
  		if (!ip6_tnl_rcv_ctl(t, &ipv6h->daddr, &ipv6h->saddr)) {
  			t->dev->stats.rx_dropped++;
  			rcu_read_unlock();
  			goto discard;
  		}
ed1efb2ae   Steffen Klassert   ipv6: Add support...
315
  		rcu_read_unlock();
fa9ad96d4   Steffen Klassert   vti6: Update the ...
316

0146dca70   Sabrina Dubroca   xfrm: add support...
317
318
319
320
  		XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6 = t;
  		XFRM_SPI_SKB_CB(skb)->family = AF_INET6;
  		XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct ipv6hdr, daddr);
  		return xfrm_input(skb, nexthdr, spi, encap_type);
ed1efb2ae   Steffen Klassert   ipv6: Add support...
321
322
  	}
  	rcu_read_unlock();
fa9ad96d4   Steffen Klassert   vti6: Update the ...
323
  	return -EINVAL;
ed1efb2ae   Steffen Klassert   ipv6: Add support...
324
325
326
327
  discard:
  	kfree_skb(skb);
  	return 0;
  }
0146dca70   Sabrina Dubroca   xfrm: add support...
328
329
330
331
332
333
  static int vti6_rcv(struct sk_buff *skb)
  {
  	int nexthdr = skb_network_header(skb)[IP6CB(skb)->nhoff];
  
  	return vti6_input_proto(skb, nexthdr, 0, 0);
  }
fa9ad96d4   Steffen Klassert   vti6: Update the ...
334
335
336
337
  static int vti6_rcv_cb(struct sk_buff *skb, int err)
  {
  	unsigned short family;
  	struct net_device *dev;
fa9ad96d4   Steffen Klassert   vti6: Update the ...
338
  	struct xfrm_state *x;
4c145dce2   Florian Westphal   xfrm: make xfrm m...
339
  	const struct xfrm_mode *inner_mode;
fa9ad96d4   Steffen Klassert   vti6: Update the ...
340
  	struct ip6_tnl *t = XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6;
d55c670cb   Alexander Duyck   ip_vti/ip6_vti: P...
341
342
  	u32 orig_mark = skb->mark;
  	int ret;
fa9ad96d4   Steffen Klassert   vti6: Update the ...
343
344
345
346
347
348
349
350
351
352
353
354
355
356
  
  	if (!t)
  		return 1;
  
  	dev = t->dev;
  
  	if (err) {
  		dev->stats.rx_errors++;
  		dev->stats.rx_dropped++;
  
  		return 0;
  	}
  
  	x = xfrm_input_state(skb);
1fb81e09d   thomas.zeitlhofer+lkml@ze-it.at   vti: use right in...
357

c9500d7b7   Florian Westphal   xfrm: store xfrm_...
358
  	inner_mode = &x->inner_mode;
1fb81e09d   thomas.zeitlhofer+lkml@ze-it.at   vti: use right in...
359
360
361
362
363
364
365
366
367
  
  	if (x->sel.family == AF_UNSPEC) {
  		inner_mode = xfrm_ip2inner_mode(x, XFRM_MODE_SKB_CB(skb)->protocol);
  		if (inner_mode == NULL) {
  			XFRM_INC_STATS(dev_net(skb->dev),
  				       LINUX_MIB_XFRMINSTATEMODEERROR);
  			return -EINVAL;
  		}
  	}
b45714b16   Florian Westphal   xfrm: prefer fami...
368
  	family = inner_mode->family;
fa9ad96d4   Steffen Klassert   vti6: Update the ...
369

d55c670cb   Alexander Duyck   ip_vti/ip6_vti: P...
370
371
372
373
374
  	skb->mark = be32_to_cpu(t->parms.i_key);
  	ret = xfrm_policy_check(NULL, XFRM_POLICY_IN, skb, family);
  	skb->mark = orig_mark;
  
  	if (!ret)
fa9ad96d4   Steffen Klassert   vti6: Update the ...
375
376
377
378
  		return -EPERM;
  
  	skb_scrub_packet(skb, !net_eq(t->net, dev_net(skb->dev)));
  	skb->dev = dev;
5711eb050   Fabian Frederick   ipv6: use dev_sw_...
379
  	dev_sw_netstats_rx_add(dev, skb->len);
fa9ad96d4   Steffen Klassert   vti6: Update the ...
380
381
382
  
  	return 0;
  }
ed1efb2ae   Steffen Klassert   ipv6: Add support...
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
  /**
   * vti6_addr_conflict - compare packet addresses to tunnel's own
   *   @t: the outgoing tunnel device
   *   @hdr: IPv6 header from the incoming packet
   *
   * Description:
   *   Avoid trivial tunneling loop by checking that tunnel exit-point
   *   doesn't match source of incoming packet.
   *
   * Return:
   *   1 if conflict,
   *   0 else
   **/
  static inline bool
  vti6_addr_conflict(const struct ip6_tnl *t, const struct ipv6hdr *hdr)
  {
  	return ipv6_addr_equal(&t->parms.raddr, &hdr->saddr);
  }
26be8e2db   Steffen Klassert   vti6: Check the t...
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
  static bool vti6_state_check(const struct xfrm_state *x,
  			     const struct in6_addr *dst,
  			     const struct in6_addr *src)
  {
  	xfrm_address_t *daddr = (xfrm_address_t *)dst;
  	xfrm_address_t *saddr = (xfrm_address_t *)src;
  
  	/* if there is no transform then this tunnel is not functional.
  	 * Or if the xfrm is not mode tunnel.
  	 */
  	if (!x || x->props.mode != XFRM_MODE_TUNNEL ||
  	    x->props.family != AF_INET6)
  		return false;
  
  	if (ipv6_addr_any(dst))
  		return xfrm_addr_equal(saddr, &x->props.saddr, AF_INET6);
  
  	if (!xfrm_state_addr_check(x, daddr, saddr, AF_INET6))
  		return false;
  
  	return true;
  }
ed1efb2ae   Steffen Klassert   ipv6: Add support...
423
424
425
426
  /**
   * vti6_xmit - send a packet
   *   @skb: the outgoing socket buffer
   *   @dev: the outgoing tunnel device
22e1b23da   Steffen Klassert   vti6: Support int...
427
   *   @fl: the flow informations for the xfrm_lookup
ed1efb2ae   Steffen Klassert   ipv6: Add support...
428
   **/
22e1b23da   Steffen Klassert   vti6: Support int...
429
430
  static int
  vti6_xmit(struct sk_buff *skb, struct net_device *dev, struct flowi *fl)
ed1efb2ae   Steffen Klassert   ipv6: Add support...
431
  {
ed1efb2ae   Steffen Klassert   ipv6: Add support...
432
433
  	struct ip6_tnl *t = netdev_priv(dev);
  	struct net_device_stats *stats = &t->dev->stats;
7c8525815   Steffen Klassert   vti6: Remove dst_...
434
  	struct dst_entry *dst = skb_dst(skb);
ed1efb2ae   Steffen Klassert   ipv6: Add support...
435
  	struct net_device *tdev;
d50051407   Steffen Klassert   ipv6: Allow sendi...
436
  	struct xfrm_state *x;
36f6ee22d   Alexey Kodanev   vti: fix use afte...
437
  	int pkt_len = skb->len;
ed1efb2ae   Steffen Klassert   ipv6: Add support...
438
  	int err = -1;
ccd740cbc   Steffen Klassert   vti6: Add pmtu ha...
439
  	int mtu;
ed1efb2ae   Steffen Klassert   ipv6: Add support...
440

95224166a   Nicolas Dichtel   vti[6]: fix packe...
441
  	if (!dst) {
f1ed10264   Nicolas Dichtel   vti[6]: fix packe...
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
  		switch (skb->protocol) {
  		case htons(ETH_P_IP): {
  			struct rtable *rt;
  
  			fl->u.ip4.flowi4_oif = dev->ifindex;
  			fl->u.ip4.flowi4_flags |= FLOWI_FLAG_ANYSRC;
  			rt = __ip_route_output_key(dev_net(dev), &fl->u.ip4);
  			if (IS_ERR(rt))
  				goto tx_err_link_failure;
  			dst = &rt->dst;
  			skb_dst_set(skb, dst);
  			break;
  		}
  		case htons(ETH_P_IPV6):
  			fl->u.ip6.flowi6_oif = dev->ifindex;
  			fl->u.ip6.flowi6_flags |= FLOWI_FLAG_ANYSRC;
  			dst = ip6_route_output(dev_net(dev), NULL, &fl->u.ip6);
  			if (dst->error) {
  				dst_release(dst);
  				dst = NULL;
  				goto tx_err_link_failure;
  			}
  			skb_dst_set(skb, dst);
  			break;
  		default:
95224166a   Nicolas Dichtel   vti[6]: fix packe...
467
468
  			goto tx_err_link_failure;
  		}
95224166a   Nicolas Dichtel   vti[6]: fix packe...
469
  	}
ed1efb2ae   Steffen Klassert   ipv6: Add support...
470

7c8525815   Steffen Klassert   vti6: Remove dst_...
471
  	dst_hold(dst);
b328ecc46   Steffen Klassert   xfrm: Make the po...
472
  	dst = xfrm_lookup_route(t->net, dst, fl, NULL, 0);
7c8525815   Steffen Klassert   vti6: Remove dst_...
473
474
475
476
  	if (IS_ERR(dst)) {
  		err = PTR_ERR(dst);
  		dst = NULL;
  		goto tx_err_link_failure;
ed1efb2ae   Steffen Klassert   ipv6: Add support...
477
  	}
b328ecc46   Steffen Klassert   xfrm: Make the po...
478
479
  	if (dst->flags & DST_XFRM_QUEUE)
  		goto queued;
d50051407   Steffen Klassert   ipv6: Allow sendi...
480
481
482
483
484
485
  	x = dst->xfrm;
  	if (!vti6_state_check(x, &t->parms.raddr, &t->parms.laddr))
  		goto tx_err_link_failure;
  
  	if (!ip6_tnl_xmit_ctl(t, (const struct in6_addr *)&x->props.saddr,
  			      (const struct in6_addr *)&x->id.daddr))
ed1efb2ae   Steffen Klassert   ipv6: Add support...
486
487
488
489
490
491
492
493
494
495
496
  		goto tx_err_link_failure;
  
  	tdev = dst->dev;
  
  	if (tdev == dev) {
  		stats->collisions++;
  		net_warn_ratelimited("%s: Local routing loop detected!
  ",
  				     t->parms.name);
  		goto tx_err_dst_release;
  	}
ccd740cbc   Steffen Klassert   vti6: Add pmtu ha...
497
  	mtu = dst_mtu(dst);
9f2895461   Alexey Kodanev   vti6: remove !skb...
498
  	if (skb->len > mtu) {
8247a79ef   Hangbin Liu   vti: do not confi...
499
  		skb_dst_update_pmtu_no_confirm(skb, mtu);
ccd740cbc   Steffen Klassert   vti6: Add pmtu ha...
500

e3dc847a5   Steffen Klassert   vti6: Don't repor...
501
502
503
  		if (skb->protocol == htons(ETH_P_IPV6)) {
  			if (mtu < IPV6_MIN_MTU)
  				mtu = IPV6_MIN_MTU;
ccd740cbc   Steffen Klassert   vti6: Add pmtu ha...
504
  			icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
e3dc847a5   Steffen Klassert   vti6: Don't repor...
505
  		} else {
ccd740cbc   Steffen Klassert   vti6: Add pmtu ha...
506
507
  			icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
  				  htonl(mtu));
e3dc847a5   Steffen Klassert   vti6: Don't repor...
508
  		}
ccd740cbc   Steffen Klassert   vti6: Add pmtu ha...
509

d6990976a   Eyal Birger   vti6: fix PMTU ca...
510
511
  		err = -EMSGSIZE;
  		goto tx_err_dst_release;
ccd740cbc   Steffen Klassert   vti6: Add pmtu ha...
512
  	}
b328ecc46   Steffen Klassert   xfrm: Make the po...
513
  queued:
d6990976a   Eyal Birger   vti6: fix PMTU ca...
514
515
516
  	skb_scrub_packet(skb, !net_eq(t->net, dev_net(dev)));
  	skb_dst_set(skb, dst);
  	skb->dev = skb_dst(skb)->dev;
13206b6bf   Eric W. Biederman   net: Pass net int...
517
  	err = dst_output(t->net, skb->sk, skb);
bb107456b   Haishuang Yan   ip6_vti: simplify...
518
519
520
  	if (net_xmit_eval(err) == 0)
  		err = pkt_len;
  	iptunnel_xmit_stats(dev, err);
ed1efb2ae   Steffen Klassert   ipv6: Add support...
521
522
523
524
525
526
  
  	return 0;
  tx_err_link_failure:
  	stats->tx_carrier_errors++;
  	dst_link_failure(skb);
  tx_err_dst_release:
7c8525815   Steffen Klassert   vti6: Remove dst_...
527
  	dst_release(dst);
ed1efb2ae   Steffen Klassert   ipv6: Add support...
528
529
530
531
532
533
534
535
  	return err;
  }
  
  static netdev_tx_t
  vti6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
  {
  	struct ip6_tnl *t = netdev_priv(dev);
  	struct net_device_stats *stats = &t->dev->stats;
22e1b23da   Steffen Klassert   vti6: Support int...
536
  	struct flowi fl;
ed1efb2ae   Steffen Klassert   ipv6: Add support...
537
  	int ret;
cb9f1b783   Willem de Bruijn   ip: validate head...
538
539
  	if (!pskb_inet_may_pull(skb))
  		goto tx_err;
22e1b23da   Steffen Klassert   vti6: Support int...
540
  	memset(&fl, 0, sizeof(fl));
22e1b23da   Steffen Klassert   vti6: Support int...
541

ed1efb2ae   Steffen Klassert   ipv6: Add support...
542
543
  	switch (skb->protocol) {
  	case htons(ETH_P_IPV6):
22e1b23da   Steffen Klassert   vti6: Support int...
544
  		if ((t->parms.proto != IPPROTO_IPV6 && t->parms.proto != 0) ||
cb9f1b783   Willem de Bruijn   ip: validate head...
545
  		    vti6_addr_conflict(t, ipv6_hdr(skb)))
22e1b23da   Steffen Klassert   vti6: Support int...
546
547
548
549
550
551
552
553
  			goto tx_err;
  
  		xfrm_decode_session(skb, &fl, AF_INET6);
  		memset(IP6CB(skb), 0, sizeof(*IP6CB(skb)));
  		break;
  	case htons(ETH_P_IP):
  		xfrm_decode_session(skb, &fl, AF_INET);
  		memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
ed1efb2ae   Steffen Klassert   ipv6: Add support...
554
555
556
557
  		break;
  	default:
  		goto tx_err;
  	}
cd5279c19   Alexander Duyck   ip_vti/ip6_vti: D...
558
559
  	/* override mark with tunnel output key */
  	fl.flowi_mark = be32_to_cpu(t->parms.o_key);
22e1b23da   Steffen Klassert   vti6: Support int...
560
  	ret = vti6_xmit(skb, dev, &fl);
ed1efb2ae   Steffen Klassert   ipv6: Add support...
561
562
563
564
565
566
567
568
569
570
571
  	if (ret < 0)
  		goto tx_err;
  
  	return NETDEV_TX_OK;
  
  tx_err:
  	stats->tx_errors++;
  	stats->tx_dropped++;
  	kfree_skb(skb);
  	return NETDEV_TX_OK;
  }
fa9ad96d4   Steffen Klassert   vti6: Update the ...
572
573
574
575
  static int vti6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
  		    u8 type, u8 code, int offset, __be32 info)
  {
  	__be32 spi;
6d004d6cc   Steffen Klassert   vti: Use the tunn...
576
  	__u32 mark;
fa9ad96d4   Steffen Klassert   vti6: Update the ...
577
578
579
580
581
582
583
584
585
586
587
588
  	struct xfrm_state *x;
  	struct ip6_tnl *t;
  	struct ip_esp_hdr *esph;
  	struct ip_auth_hdr *ah;
  	struct ip_comp_hdr *ipch;
  	struct net *net = dev_net(skb->dev);
  	const struct ipv6hdr *iph = (const struct ipv6hdr *)skb->data;
  	int protocol = iph->nexthdr;
  
  	t = vti6_tnl_lookup(dev_net(skb->dev), &iph->daddr, &iph->saddr);
  	if (!t)
  		return -1;
6d004d6cc   Steffen Klassert   vti: Use the tunn...
589
  	mark = be32_to_cpu(t->parms.o_key);
fa9ad96d4   Steffen Klassert   vti6: Update the ...
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
  	switch (protocol) {
  	case IPPROTO_ESP:
  		esph = (struct ip_esp_hdr *)(skb->data + offset);
  		spi = esph->spi;
  		break;
  	case IPPROTO_AH:
  		ah = (struct ip_auth_hdr *)(skb->data + offset);
  		spi = ah->spi;
  		break;
  	case IPPROTO_COMP:
  		ipch = (struct ip_comp_hdr *)(skb->data + offset);
  		spi = htonl(ntohs(ipch->cpi));
  		break;
  	default:
  		return 0;
  	}
  
  	if (type != ICMPV6_PKT_TOOBIG &&
  	    type != NDISC_REDIRECT)
  		return 0;
6d004d6cc   Steffen Klassert   vti: Use the tunn...
610
  	x = xfrm_state_lookup(net, mark, (const xfrm_address_t *)&iph->daddr,
fa9ad96d4   Steffen Klassert   vti6: Update the ...
611
612
613
614
615
  			      spi, protocol, AF_INET6);
  	if (!x)
  		return 0;
  
  	if (type == NDISC_REDIRECT)
e2d118a1c   Lorenzo Colitti   net: inet: Suppor...
616
617
  		ip6_redirect(skb, net, skb->dev->ifindex, 0,
  			     sock_net_uid(net, NULL));
fa9ad96d4   Steffen Klassert   vti6: Update the ...
618
  	else
e2d118a1c   Lorenzo Colitti   net: inet: Suppor...
619
  		ip6_update_pmtu(skb, net, info, 0, 0, sock_net_uid(net, NULL));
fa9ad96d4   Steffen Klassert   vti6: Update the ...
620
621
622
623
  	xfrm_state_put(x);
  
  	return 0;
  }
7a67e69a3   Stefano Brivio   vti6: Keep set MT...
624
  static void vti6_link_config(struct ip6_tnl *t, bool keep_mtu)
ed1efb2ae   Steffen Klassert   ipv6: Add support...
625
  {
ed1efb2ae   Steffen Klassert   ipv6: Add support...
626
627
  	struct net_device *dev = t->dev;
  	struct __ip6_tnl_parm *p = &t->parms;
53c81e95d   Alexey Kodanev   ip6_vti: adjust v...
628
  	struct net_device *tdev = NULL;
c6741fbed   Stefano Brivio   vti6: Properly ad...
629
  	int mtu;
ed1efb2ae   Steffen Klassert   ipv6: Add support...
630
631
632
  
  	memcpy(dev->dev_addr, &p->laddr, sizeof(struct in6_addr));
  	memcpy(dev->broadcast, &p->raddr, sizeof(struct in6_addr));
ed1efb2ae   Steffen Klassert   ipv6: Add support...
633
634
635
636
637
638
639
640
  	p->flags &= ~(IP6_TNL_F_CAP_XMIT | IP6_TNL_F_CAP_RCV |
  		      IP6_TNL_F_CAP_PER_PACKET);
  	p->flags |= ip6_tnl_get_cap(t, &p->laddr, &p->raddr);
  
  	if (p->flags & IP6_TNL_F_CAP_XMIT && p->flags & IP6_TNL_F_CAP_RCV)
  		dev->flags |= IFF_POINTOPOINT;
  	else
  		dev->flags &= ~IFF_POINTOPOINT;
53c81e95d   Alexey Kodanev   ip6_vti: adjust v...
641

7a67e69a3   Stefano Brivio   vti6: Keep set MT...
642
643
644
645
  	if (keep_mtu && dev->mtu) {
  		dev->mtu = clamp(dev->mtu, dev->min_mtu, dev->max_mtu);
  		return;
  	}
53c81e95d   Alexey Kodanev   ip6_vti: adjust v...
646
647
648
649
650
  	if (p->flags & IP6_TNL_F_CAP_XMIT) {
  		int strict = (ipv6_addr_type(&p->raddr) &
  			      (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL));
  		struct rt6_info *rt = rt6_lookup(t->net,
  						 &p->raddr, &p->laddr,
b75cc8f90   David Ahern   net/ipv6: Pass sk...
651
  						 p->link, NULL, strict);
53c81e95d   Alexey Kodanev   ip6_vti: adjust v...
652
653
654
655
656
657
658
659
660
661
  
  		if (rt)
  			tdev = rt->dst.dev;
  		ip6_rt_put(rt);
  	}
  
  	if (!tdev && p->link)
  		tdev = __dev_get_by_index(t->net, p->link);
  
  	if (tdev)
c6741fbed   Stefano Brivio   vti6: Properly ad...
662
663
664
  		mtu = tdev->mtu - sizeof(struct ipv6hdr);
  	else
  		mtu = ETH_DATA_LEN - LL_MAX_HEADER - sizeof(struct ipv6hdr);
b4331a681   Stefano Brivio   vti6: Change mini...
665
  	dev->mtu = max_t(int, mtu, IPV4_MIN_MTU);
ed1efb2ae   Steffen Klassert   ipv6: Add support...
666
667
668
669
670
671
  }
  
  /**
   * vti6_tnl_change - update the tunnel parameters
   *   @t: tunnel to be changed
   *   @p: tunnel configuration parameters
7a67e69a3   Stefano Brivio   vti6: Keep set MT...
672
   *   @keep_mtu: MTU was set from userspace, don't re-compute it
ed1efb2ae   Steffen Klassert   ipv6: Add support...
673
674
675
676
677
   *
   * Description:
   *   vti6_tnl_change() updates the tunnel parameters
   **/
  static int
7a67e69a3   Stefano Brivio   vti6: Keep set MT...
678
679
  vti6_tnl_change(struct ip6_tnl *t, const struct __ip6_tnl_parm *p,
  		bool keep_mtu)
ed1efb2ae   Steffen Klassert   ipv6: Add support...
680
681
682
683
684
685
686
  {
  	t->parms.laddr = p->laddr;
  	t->parms.raddr = p->raddr;
  	t->parms.link = p->link;
  	t->parms.i_key = p->i_key;
  	t->parms.o_key = p->o_key;
  	t->parms.proto = p->proto;
0a473b82c   Craig Gallek   ip6_tunnel: Allow...
687
  	t->parms.fwmark = p->fwmark;
607f725f6   Paolo Abeni   net: replace dst_...
688
  	dst_cache_reset(&t->dst_cache);
7a67e69a3   Stefano Brivio   vti6: Keep set MT...
689
  	vti6_link_config(t, keep_mtu);
ed1efb2ae   Steffen Klassert   ipv6: Add support...
690
691
  	return 0;
  }
7a67e69a3   Stefano Brivio   vti6: Keep set MT...
692
693
  static int vti6_update(struct ip6_tnl *t, struct __ip6_tnl_parm *p,
  		       bool keep_mtu)
ed1efb2ae   Steffen Klassert   ipv6: Add support...
694
695
696
697
698
699
700
  {
  	struct net *net = dev_net(t->dev);
  	struct vti6_net *ip6n = net_generic(net, vti6_net_id);
  	int err;
  
  	vti6_tnl_unlink(ip6n, t);
  	synchronize_net();
7a67e69a3   Stefano Brivio   vti6: Keep set MT...
701
  	err = vti6_tnl_change(t, p, keep_mtu);
ed1efb2ae   Steffen Klassert   ipv6: Add support...
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
  	vti6_tnl_link(ip6n, t);
  	netdev_state_change(t->dev);
  	return err;
  }
  
  static void
  vti6_parm_from_user(struct __ip6_tnl_parm *p, const struct ip6_tnl_parm2 *u)
  {
  	p->laddr = u->laddr;
  	p->raddr = u->raddr;
  	p->link = u->link;
  	p->i_key = u->i_key;
  	p->o_key = u->o_key;
  	p->proto = u->proto;
  
  	memcpy(p->name, u->name, sizeof(u->name));
  }
  
  static void
  vti6_parm_to_user(struct ip6_tnl_parm2 *u, const struct __ip6_tnl_parm *p)
  {
  	u->laddr = p->laddr;
  	u->raddr = p->raddr;
  	u->link = p->link;
  	u->i_key = p->i_key;
  	u->o_key = p->o_key;
7dcdf941c   David Forster   vti6: return GRE_...
728
729
730
731
  	if (u->i_key)
  		u->i_flags |= GRE_KEY;
  	if (u->o_key)
  		u->o_flags |= GRE_KEY;
ed1efb2ae   Steffen Klassert   ipv6: Add support...
732
733
734
735
736
737
  	u->proto = p->proto;
  
  	memcpy(u->name, p->name, sizeof(u->name));
  }
  
  /**
154a8c46b   Sun Lianwen   change the commen...
738
   * vti6_ioctl - configure vti6 tunnels from userspace
ed1efb2ae   Steffen Klassert   ipv6: Add support...
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
   *   @dev: virtual device associated with tunnel
   *   @ifr: parameters passed from userspace
   *   @cmd: command to be performed
   *
   * Description:
   *   vti6_ioctl() is used for managing vti6 tunnels
   *   from userspace.
   *
   *   The possible commands are the following:
   *     %SIOCGETTUNNEL: get tunnel parameters for device
   *     %SIOCADDTUNNEL: add tunnel matching given tunnel parameters
   *     %SIOCCHGTUNNEL: change tunnel parameters to those given
   *     %SIOCDELTUNNEL: delete tunnel
   *
   *   The fallback device "ip6_vti0", created during module
   *   initialization, can be used for creating other tunnel devices.
   *
   * Return:
   *   0 on success,
   *   %-EFAULT if unable to copy data to or from userspace,
   *   %-EPERM if current process hasn't %CAP_NET_ADMIN set
   *   %-EINVAL if passed tunnel parameters are invalid,
   *   %-EEXIST if changing a tunnel's parameters would cause a conflict
   *   %-ENODEV if attempting to change or delete a nonexisting device
   **/
  static int
  vti6_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
  {
  	int err = 0;
  	struct ip6_tnl_parm2 p;
  	struct __ip6_tnl_parm p1;
  	struct ip6_tnl *t = NULL;
  	struct net *net = dev_net(dev);
  	struct vti6_net *ip6n = net_generic(net, vti6_net_id);
  
  	switch (cmd) {
  	case SIOCGETTUNNEL:
  		if (dev == ip6n->fb_tnl_dev) {
  			if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) {
  				err = -EFAULT;
  				break;
  			}
  			vti6_parm_from_user(&p1, &p);
  			t = vti6_locate(net, &p1, 0);
  		} else {
  			memset(&p, 0, sizeof(p));
  		}
63159f29b   Ian Morris   ipv6: coding styl...
786
  		if (!t)
ed1efb2ae   Steffen Klassert   ipv6: Add support...
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
  			t = netdev_priv(dev);
  		vti6_parm_to_user(&p, &t->parms);
  		if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p)))
  			err = -EFAULT;
  		break;
  	case SIOCADDTUNNEL:
  	case SIOCCHGTUNNEL:
  		err = -EPERM;
  		if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
  			break;
  		err = -EFAULT;
  		if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
  			break;
  		err = -EINVAL;
  		if (p.proto != IPPROTO_IPV6  && p.proto != 0)
  			break;
  		vti6_parm_from_user(&p1, &p);
  		t = vti6_locate(net, &p1, cmd == SIOCADDTUNNEL);
  		if (dev != ip6n->fb_tnl_dev && cmd == SIOCCHGTUNNEL) {
53b24b8f9   Ian Morris   ipv6: coding styl...
806
  			if (t) {
ed1efb2ae   Steffen Klassert   ipv6: Add support...
807
808
809
810
811
812
  				if (t->dev != dev) {
  					err = -EEXIST;
  					break;
  				}
  			} else
  				t = netdev_priv(dev);
7a67e69a3   Stefano Brivio   vti6: Keep set MT...
813
  			err = vti6_update(t, &p1, false);
ed1efb2ae   Steffen Klassert   ipv6: Add support...
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
  		}
  		if (t) {
  			err = 0;
  			vti6_parm_to_user(&p, &t->parms);
  			if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p)))
  				err = -EFAULT;
  
  		} else
  			err = (cmd == SIOCADDTUNNEL ? -ENOBUFS : -ENOENT);
  		break;
  	case SIOCDELTUNNEL:
  		err = -EPERM;
  		if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
  			break;
  
  		if (dev == ip6n->fb_tnl_dev) {
  			err = -EFAULT;
  			if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
  				break;
  			err = -ENOENT;
  			vti6_parm_from_user(&p1, &p);
  			t = vti6_locate(net, &p1, 0);
63159f29b   Ian Morris   ipv6: coding styl...
836
  			if (!t)
ed1efb2ae   Steffen Klassert   ipv6: Add support...
837
838
839
840
841
842
843
844
845
846
847
848
849
850
  				break;
  			err = -EPERM;
  			if (t->dev == ip6n->fb_tnl_dev)
  				break;
  			dev = t->dev;
  		}
  		err = 0;
  		unregister_netdevice(dev);
  		break;
  	default:
  		err = -EINVAL;
  	}
  	return err;
  }
ed1efb2ae   Steffen Klassert   ipv6: Add support...
851
  static const struct net_device_ops vti6_netdev_ops = {
16a0231bf   Steffen Klassert   vti6: Use vti6_de...
852
  	.ndo_init	= vti6_dev_init,
ed1efb2ae   Steffen Klassert   ipv6: Add support...
853
854
855
  	.ndo_uninit	= vti6_dev_uninit,
  	.ndo_start_xmit = vti6_tnl_xmit,
  	.ndo_do_ioctl	= vti6_ioctl,
469bdcefd   Li RongQing   ipv6: fix the use...
856
  	.ndo_get_stats64 = ip_tunnel_get_stats64,
ecf2c06a8   Nicolas Dichtel   ip6tnl,gre6,vti6:...
857
  	.ndo_get_iflink = ip6_tnl_get_iflink,
ed1efb2ae   Steffen Klassert   ipv6: Add support...
858
859
860
861
862
863
864
865
866
867
868
  };
  
  /**
   * vti6_dev_setup - setup virtual tunnel device
   *   @dev: virtual device associated with tunnel
   *
   * Description:
   *   Initialize function pointers and device parameters
   **/
  static void vti6_dev_setup(struct net_device *dev)
  {
ed1efb2ae   Steffen Klassert   ipv6: Add support...
869
  	dev->netdev_ops = &vti6_netdev_ops;
ab59d2b69   Jason A. Donenfeld   net: vti: impleme...
870
  	dev->header_ops = &ip_tunnel_header_ops;
cf124db56   David S. Miller   net: Fix inconsis...
871
872
  	dev->needs_free_netdev = true;
  	dev->priv_destructor = vti6_dev_free;
ed1efb2ae   Steffen Klassert   ipv6: Add support...
873
874
  
  	dev->type = ARPHRD_TUNNEL6;
b4331a681   Stefano Brivio   vti6: Change mini...
875
  	dev->min_mtu = IPV4_MIN_MTU;
f8a554b4a   Stefano Brivio   vti6: Fix dev->ma...
876
  	dev->max_mtu = IP_MAX_MTU - sizeof(struct ipv6hdr);
ed1efb2ae   Steffen Klassert   ipv6: Add support...
877
878
  	dev->flags |= IFF_NOARP;
  	dev->addr_len = sizeof(struct in6_addr);
028758788   Eric Dumazet   net: better IFF_X...
879
  	netif_keep_dst(dev);
45ce0fd19   Felix Jia   net/ipv6: support...
880
881
882
  	/* This perm addr will be used as interface identifier by IPv6 */
  	dev->addr_assign_type = NET_ADDR_RANDOM;
  	eth_random_addr(dev->perm_addr);
ed1efb2ae   Steffen Klassert   ipv6: Add support...
883
884
885
886
887
888
889
890
891
892
893
894
  }
  
  /**
   * vti6_dev_init_gen - general initializer for all tunnel devices
   *   @dev: virtual device associated with tunnel
   **/
  static inline int vti6_dev_init_gen(struct net_device *dev)
  {
  	struct ip6_tnl *t = netdev_priv(dev);
  
  	t->dev = dev;
  	t->net = dev_net(dev);
1c213bd24   WANG Cong   net: introduce ne...
895
  	dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
ed1efb2ae   Steffen Klassert   ipv6: Add support...
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
  	if (!dev->tstats)
  		return -ENOMEM;
  	return 0;
  }
  
  /**
   * vti6_dev_init - initializer for all non fallback tunnel devices
   *   @dev: virtual device associated with tunnel
   **/
  static int vti6_dev_init(struct net_device *dev)
  {
  	struct ip6_tnl *t = netdev_priv(dev);
  	int err = vti6_dev_init_gen(dev);
  
  	if (err)
  		return err;
7a67e69a3   Stefano Brivio   vti6: Keep set MT...
912
  	vti6_link_config(t, true);
ed1efb2ae   Steffen Klassert   ipv6: Add support...
913
914
915
916
917
918
919
920
921
922
923
924
925
926
  	return 0;
  }
  
  /**
   * vti6_fb_tnl_dev_init - initializer for fallback tunnel device
   *   @dev: fallback device
   *
   * Return: 0
   **/
  static int __net_init vti6_fb_tnl_dev_init(struct net_device *dev)
  {
  	struct ip6_tnl *t = netdev_priv(dev);
  	struct net *net = dev_net(dev);
  	struct vti6_net *ip6n = net_generic(net, vti6_net_id);
ed1efb2ae   Steffen Klassert   ipv6: Add support...
927
928
929
  
  	t->parms.proto = IPPROTO_IPV6;
  	dev_hold(dev);
ed1efb2ae   Steffen Klassert   ipv6: Add support...
930
931
932
  	rcu_assign_pointer(ip6n->tnls_wc[0], t);
  	return 0;
  }
a8b8a889e   Matthias Schiffer   net: add netlink_...
933
934
  static int vti6_validate(struct nlattr *tb[], struct nlattr *data[],
  			 struct netlink_ext_ack *extack)
ed1efb2ae   Steffen Klassert   ipv6: Add support...
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
  {
  	return 0;
  }
  
  static void vti6_netlink_parms(struct nlattr *data[],
  			       struct __ip6_tnl_parm *parms)
  {
  	memset(parms, 0, sizeof(*parms));
  
  	if (!data)
  		return;
  
  	if (data[IFLA_VTI_LINK])
  		parms->link = nla_get_u32(data[IFLA_VTI_LINK]);
  
  	if (data[IFLA_VTI_LOCAL])
67b61f6c1   Jiri Benc   netlink: implemen...
951
  		parms->laddr = nla_get_in6_addr(data[IFLA_VTI_LOCAL]);
ed1efb2ae   Steffen Klassert   ipv6: Add support...
952
953
  
  	if (data[IFLA_VTI_REMOTE])
67b61f6c1   Jiri Benc   netlink: implemen...
954
  		parms->raddr = nla_get_in6_addr(data[IFLA_VTI_REMOTE]);
ed1efb2ae   Steffen Klassert   ipv6: Add support...
955
956
957
958
959
960
  
  	if (data[IFLA_VTI_IKEY])
  		parms->i_key = nla_get_be32(data[IFLA_VTI_IKEY]);
  
  	if (data[IFLA_VTI_OKEY])
  		parms->o_key = nla_get_be32(data[IFLA_VTI_OKEY]);
0a473b82c   Craig Gallek   ip6_tunnel: Allow...
961
962
963
  
  	if (data[IFLA_VTI_FWMARK])
  		parms->fwmark = nla_get_u32(data[IFLA_VTI_FWMARK]);
ed1efb2ae   Steffen Klassert   ipv6: Add support...
964
965
966
  }
  
  static int vti6_newlink(struct net *src_net, struct net_device *dev,
7a3f4a185   Matthias Schiffer   net: add netlink_...
967
968
  			struct nlattr *tb[], struct nlattr *data[],
  			struct netlink_ext_ack *extack)
ed1efb2ae   Steffen Klassert   ipv6: Add support...
969
970
971
972
973
974
975
976
977
978
979
980
981
982
  {
  	struct net *net = dev_net(dev);
  	struct ip6_tnl *nt;
  
  	nt = netdev_priv(dev);
  	vti6_netlink_parms(data, &nt->parms);
  
  	nt->parms.proto = IPPROTO_IPV6;
  
  	if (vti6_locate(net, &nt->parms, 0))
  		return -EEXIST;
  
  	return vti6_tnl_create2(dev);
  }
20ea60ca9   lucien   ip_tunnel: the la...
983
984
985
986
987
988
989
990
  static void vti6_dellink(struct net_device *dev, struct list_head *head)
  {
  	struct net *net = dev_net(dev);
  	struct vti6_net *ip6n = net_generic(net, vti6_net_id);
  
  	if (dev != ip6n->fb_tnl_dev)
  		unregister_netdevice_queue(dev, head);
  }
ed1efb2ae   Steffen Klassert   ipv6: Add support...
991
  static int vti6_changelink(struct net_device *dev, struct nlattr *tb[],
ad744b223   Matthias Schiffer   net: add netlink_...
992
993
  			   struct nlattr *data[],
  			   struct netlink_ext_ack *extack)
ed1efb2ae   Steffen Klassert   ipv6: Add support...
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
  {
  	struct ip6_tnl *t;
  	struct __ip6_tnl_parm p;
  	struct net *net = dev_net(dev);
  	struct vti6_net *ip6n = net_generic(net, vti6_net_id);
  
  	if (dev == ip6n->fb_tnl_dev)
  		return -EINVAL;
  
  	vti6_netlink_parms(data, &p);
  
  	t = vti6_locate(net, &p, 0);
  
  	if (t) {
  		if (t->dev != dev)
  			return -EEXIST;
  	} else
  		t = netdev_priv(dev);
7a67e69a3   Stefano Brivio   vti6: Keep set MT...
1012
  	return vti6_update(t, &p, tb && tb[IFLA_MTU]);
ed1efb2ae   Steffen Klassert   ipv6: Add support...
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
  }
  
  static size_t vti6_get_size(const struct net_device *dev)
  {
  	return
  		/* IFLA_VTI_LINK */
  		nla_total_size(4) +
  		/* IFLA_VTI_LOCAL */
  		nla_total_size(sizeof(struct in6_addr)) +
  		/* IFLA_VTI_REMOTE */
  		nla_total_size(sizeof(struct in6_addr)) +
  		/* IFLA_VTI_IKEY */
  		nla_total_size(4) +
  		/* IFLA_VTI_OKEY */
  		nla_total_size(4) +
0a473b82c   Craig Gallek   ip6_tunnel: Allow...
1028
1029
  		/* IFLA_VTI_FWMARK */
  		nla_total_size(4) +
ed1efb2ae   Steffen Klassert   ipv6: Add support...
1030
1031
1032
1033
1034
1035
1036
1037
1038
  		0;
  }
  
  static int vti6_fill_info(struct sk_buff *skb, const struct net_device *dev)
  {
  	struct ip6_tnl *tunnel = netdev_priv(dev);
  	struct __ip6_tnl_parm *parm = &tunnel->parms;
  
  	if (nla_put_u32(skb, IFLA_VTI_LINK, parm->link) ||
930345ea6   Jiri Benc   netlink: implemen...
1039
1040
  	    nla_put_in6_addr(skb, IFLA_VTI_LOCAL, &parm->laddr) ||
  	    nla_put_in6_addr(skb, IFLA_VTI_REMOTE, &parm->raddr) ||
ed1efb2ae   Steffen Klassert   ipv6: Add support...
1041
  	    nla_put_be32(skb, IFLA_VTI_IKEY, parm->i_key) ||
0a473b82c   Craig Gallek   ip6_tunnel: Allow...
1042
1043
  	    nla_put_be32(skb, IFLA_VTI_OKEY, parm->o_key) ||
  	    nla_put_u32(skb, IFLA_VTI_FWMARK, parm->fwmark))
ed1efb2ae   Steffen Klassert   ipv6: Add support...
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
  		goto nla_put_failure;
  	return 0;
  
  nla_put_failure:
  	return -EMSGSIZE;
  }
  
  static const struct nla_policy vti6_policy[IFLA_VTI_MAX + 1] = {
  	[IFLA_VTI_LINK]		= { .type = NLA_U32 },
  	[IFLA_VTI_LOCAL]	= { .len = sizeof(struct in6_addr) },
  	[IFLA_VTI_REMOTE]	= { .len = sizeof(struct in6_addr) },
  	[IFLA_VTI_IKEY]		= { .type = NLA_U32 },
  	[IFLA_VTI_OKEY]		= { .type = NLA_U32 },
0a473b82c   Craig Gallek   ip6_tunnel: Allow...
1057
  	[IFLA_VTI_FWMARK]	= { .type = NLA_U32 },
ed1efb2ae   Steffen Klassert   ipv6: Add support...
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
  };
  
  static struct rtnl_link_ops vti6_link_ops __read_mostly = {
  	.kind		= "vti6",
  	.maxtype	= IFLA_VTI_MAX,
  	.policy		= vti6_policy,
  	.priv_size	= sizeof(struct ip6_tnl),
  	.setup		= vti6_dev_setup,
  	.validate	= vti6_validate,
  	.newlink	= vti6_newlink,
20ea60ca9   lucien   ip_tunnel: the la...
1068
  	.dellink	= vti6_dellink,
ed1efb2ae   Steffen Klassert   ipv6: Add support...
1069
1070
1071
  	.changelink	= vti6_changelink,
  	.get_size	= vti6_get_size,
  	.fill_info	= vti6_fill_info,
1728d4fab   Nicolas Dichtel   tunnels: advertis...
1072
  	.get_link_net	= ip6_tnl_get_link_net,
ed1efb2ae   Steffen Klassert   ipv6: Add support...
1073
  };
bb401caef   Eric Dumazet   ipv6: speedup ipv...
1074
1075
  static void __net_exit vti6_destroy_tunnels(struct vti6_net *ip6n,
  					    struct list_head *list)
ed1efb2ae   Steffen Klassert   ipv6: Add support...
1076
1077
1078
  {
  	int h;
  	struct ip6_tnl *t;
ed1efb2ae   Steffen Klassert   ipv6: Add support...
1079

e87a8f24c   Jiri Kosina   net: resolve symb...
1080
  	for (h = 0; h < IP6_VTI_HASH_SIZE; h++) {
ed1efb2ae   Steffen Klassert   ipv6: Add support...
1081
  		t = rtnl_dereference(ip6n->tnls_r_l[h]);
53b24b8f9   Ian Morris   ipv6: coding styl...
1082
  		while (t) {
bb401caef   Eric Dumazet   ipv6: speedup ipv...
1083
  			unregister_netdevice_queue(t->dev, list);
ed1efb2ae   Steffen Klassert   ipv6: Add support...
1084
1085
1086
1087
1088
  			t = rtnl_dereference(t->next);
  		}
  	}
  
  	t = rtnl_dereference(ip6n->tnls_wc[0]);
9c86336c1   Haishuang Yan   ip6_vti: fix a nu...
1089
1090
  	if (t)
  		unregister_netdevice_queue(t->dev, list);
ed1efb2ae   Steffen Klassert   ipv6: Add support...
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
  }
  
  static int __net_init vti6_init_net(struct net *net)
  {
  	struct vti6_net *ip6n = net_generic(net, vti6_net_id);
  	struct ip6_tnl *t = NULL;
  	int err;
  
  	ip6n->tnls[0] = ip6n->tnls_wc;
  	ip6n->tnls[1] = ip6n->tnls_r_l;
e2948e5af   Haishuang Yan   ip6_vti: fix crea...
1101
1102
  	if (!net_has_fallback_tunnels(net))
  		return 0;
ed1efb2ae   Steffen Klassert   ipv6: Add support...
1103
1104
  	err = -ENOMEM;
  	ip6n->fb_tnl_dev = alloc_netdev(sizeof(struct ip6_tnl), "ip6_vti0",
c835a6773   Tom Gundersen   net: set name_ass...
1105
  					NET_NAME_UNKNOWN, vti6_dev_setup);
ed1efb2ae   Steffen Klassert   ipv6: Add support...
1106
1107
1108
1109
  
  	if (!ip6n->fb_tnl_dev)
  		goto err_alloc_dev;
  	dev_net_set(ip6n->fb_tnl_dev, net);
20ea60ca9   lucien   ip_tunnel: the la...
1110
  	ip6n->fb_tnl_dev->rtnl_link_ops = &vti6_link_ops;
ed1efb2ae   Steffen Klassert   ipv6: Add support...
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
  
  	err = vti6_fb_tnl_dev_init(ip6n->fb_tnl_dev);
  	if (err < 0)
  		goto err_register;
  
  	err = register_netdev(ip6n->fb_tnl_dev);
  	if (err < 0)
  		goto err_register;
  
  	t = netdev_priv(ip6n->fb_tnl_dev);
  
  	strcpy(t->parms.name, ip6n->fb_tnl_dev->name);
  	return 0;
  
  err_register:
cf124db56   David S. Miller   net: Fix inconsis...
1126
  	free_netdev(ip6n->fb_tnl_dev);
ed1efb2ae   Steffen Klassert   ipv6: Add support...
1127
1128
1129
  err_alloc_dev:
  	return err;
  }
bb401caef   Eric Dumazet   ipv6: speedup ipv...
1130
  static void __net_exit vti6_exit_batch_net(struct list_head *net_list)
ed1efb2ae   Steffen Klassert   ipv6: Add support...
1131
  {
bb401caef   Eric Dumazet   ipv6: speedup ipv...
1132
1133
1134
  	struct vti6_net *ip6n;
  	struct net *net;
  	LIST_HEAD(list);
ed1efb2ae   Steffen Klassert   ipv6: Add support...
1135
1136
  
  	rtnl_lock();
bb401caef   Eric Dumazet   ipv6: speedup ipv...
1137
1138
1139
1140
1141
  	list_for_each_entry(net, net_list, exit_list) {
  		ip6n = net_generic(net, vti6_net_id);
  		vti6_destroy_tunnels(ip6n, &list);
  	}
  	unregister_netdevice_many(&list);
ed1efb2ae   Steffen Klassert   ipv6: Add support...
1142
1143
1144
1145
1146
  	rtnl_unlock();
  }
  
  static struct pernet_operations vti6_net_ops = {
  	.init = vti6_init_net,
bb401caef   Eric Dumazet   ipv6: speedup ipv...
1147
  	.exit_batch = vti6_exit_batch_net,
ed1efb2ae   Steffen Klassert   ipv6: Add support...
1148
1149
1150
  	.id   = &vti6_net_id,
  	.size = sizeof(struct vti6_net),
  };
fa9ad96d4   Steffen Klassert   vti6: Update the ...
1151
1152
  static struct xfrm6_protocol vti_esp6_protocol __read_mostly = {
  	.handler	=	vti6_rcv,
0146dca70   Sabrina Dubroca   xfrm: add support...
1153
  	.input_handler	=	vti6_input_proto,
fa9ad96d4   Steffen Klassert   vti6: Update the ...
1154
1155
1156
1157
1158
1159
1160
  	.cb_handler	=	vti6_rcv_cb,
  	.err_handler	=	vti6_err,
  	.priority	=	100,
  };
  
  static struct xfrm6_protocol vti_ah6_protocol __read_mostly = {
  	.handler	=	vti6_rcv,
0146dca70   Sabrina Dubroca   xfrm: add support...
1161
  	.input_handler	=	vti6_input_proto,
fa9ad96d4   Steffen Klassert   vti6: Update the ...
1162
1163
1164
1165
1166
1167
1168
  	.cb_handler	=	vti6_rcv_cb,
  	.err_handler	=	vti6_err,
  	.priority	=	100,
  };
  
  static struct xfrm6_protocol vti_ipcomp6_protocol __read_mostly = {
  	.handler	=	vti6_rcv,
0146dca70   Sabrina Dubroca   xfrm: add support...
1169
  	.input_handler	=	vti6_input_proto,
fa9ad96d4   Steffen Klassert   vti6: Update the ...
1170
1171
1172
1173
  	.cb_handler	=	vti6_rcv_cb,
  	.err_handler	=	vti6_err,
  	.priority	=	100,
  };
96a208295   Xin Long   ip6_vti: use IS_R...
1174
  #if IS_REACHABLE(CONFIG_INET6_XFRM_TUNNEL)
08622869e   Xin Long   ip6_vti: support ...
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
  static int vti6_rcv_tunnel(struct sk_buff *skb)
  {
  	const xfrm_address_t *saddr;
  	__be32 spi;
  
  	saddr = (const xfrm_address_t *)&ipv6_hdr(skb)->saddr;
  	spi = xfrm6_tunnel_spi_lookup(dev_net(skb->dev), saddr);
  
  	return vti6_input_proto(skb, IPPROTO_IPV6, spi, 0);
  }
  
  static struct xfrm6_tunnel vti_ipv6_handler __read_mostly = {
  	.handler	=	vti6_rcv_tunnel,
  	.cb_handler	=	vti6_rcv_cb,
  	.err_handler	=	vti6_err,
  	.priority	=	0,
  };
a87571479   Xin Long   ip6_vti: not regi...
1192
1193
1194
1195
1196
1197
1198
  
  static struct xfrm6_tunnel vti_ip6ip_handler __read_mostly = {
  	.handler	=	vti6_rcv_tunnel,
  	.cb_handler	=	vti6_rcv_cb,
  	.err_handler	=	vti6_err,
  	.priority	=	0,
  };
08622869e   Xin Long   ip6_vti: support ...
1199
  #endif
ed1efb2ae   Steffen Klassert   ipv6: Add support...
1200
1201
1202
1203
1204
1205
1206
  /**
   * vti6_tunnel_init - register protocol and reserve needed resources
   *
   * Return: 0 on success
   **/
  static int __init vti6_tunnel_init(void)
  {
e59d82fd3   Mathias Krause   vti6: Simplify er...
1207
1208
  	const char *msg;
  	int err;
ed1efb2ae   Steffen Klassert   ipv6: Add support...
1209

e59d82fd3   Mathias Krause   vti6: Simplify er...
1210
  	msg = "tunnel device";
ed1efb2ae   Steffen Klassert   ipv6: Add support...
1211
1212
  	err = register_pernet_device(&vti6_net_ops);
  	if (err < 0)
e59d82fd3   Mathias Krause   vti6: Simplify er...
1213
  		goto pernet_dev_failed;
ed1efb2ae   Steffen Klassert   ipv6: Add support...
1214

e59d82fd3   Mathias Krause   vti6: Simplify er...
1215
  	msg = "tunnel protocols";
fa9ad96d4   Steffen Klassert   vti6: Update the ...
1216
  	err = xfrm6_protocol_register(&vti_esp6_protocol, IPPROTO_ESP);
e59d82fd3   Mathias Krause   vti6: Simplify er...
1217
1218
  	if (err < 0)
  		goto xfrm_proto_esp_failed;
fa9ad96d4   Steffen Klassert   vti6: Update the ...
1219
  	err = xfrm6_protocol_register(&vti_ah6_protocol, IPPROTO_AH);
e59d82fd3   Mathias Krause   vti6: Simplify er...
1220
1221
  	if (err < 0)
  		goto xfrm_proto_ah_failed;
fa9ad96d4   Steffen Klassert   vti6: Update the ...
1222
  	err = xfrm6_protocol_register(&vti_ipcomp6_protocol, IPPROTO_COMP);
e59d82fd3   Mathias Krause   vti6: Simplify er...
1223
1224
  	if (err < 0)
  		goto xfrm_proto_comp_failed;
96a208295   Xin Long   ip6_vti: use IS_R...
1225
  #if IS_REACHABLE(CONFIG_INET6_XFRM_TUNNEL)
08622869e   Xin Long   ip6_vti: support ...
1226
1227
1228
  	msg = "ipv6 tunnel";
  	err = xfrm6_tunnel_register(&vti_ipv6_handler, AF_INET6);
  	if (err < 0)
2ab110cbb   Xin Long   ip6_vti: support ...
1229
  		goto vti_tunnel_ipv6_failed;
a87571479   Xin Long   ip6_vti: not regi...
1230
  	err = xfrm6_tunnel_register(&vti_ip6ip_handler, AF_INET);
2ab110cbb   Xin Long   ip6_vti: support ...
1231
1232
  	if (err < 0)
  		goto vti_tunnel_ip6ip_failed;
08622869e   Xin Long   ip6_vti: support ...
1233
  #endif
fa9ad96d4   Steffen Klassert   vti6: Update the ...
1234

e59d82fd3   Mathias Krause   vti6: Simplify er...
1235
  	msg = "netlink interface";
ed1efb2ae   Steffen Klassert   ipv6: Add support...
1236
1237
1238
1239
1240
1241
1242
  	err = rtnl_link_register(&vti6_link_ops);
  	if (err < 0)
  		goto rtnl_link_failed;
  
  	return 0;
  
  rtnl_link_failed:
96a208295   Xin Long   ip6_vti: use IS_R...
1243
  #if IS_REACHABLE(CONFIG_INET6_XFRM_TUNNEL)
a87571479   Xin Long   ip6_vti: not regi...
1244
  	err = xfrm6_tunnel_deregister(&vti_ip6ip_handler, AF_INET);
2ab110cbb   Xin Long   ip6_vti: support ...
1245
  vti_tunnel_ip6ip_failed:
08622869e   Xin Long   ip6_vti: support ...
1246
  	err = xfrm6_tunnel_deregister(&vti_ipv6_handler, AF_INET6);
2ab110cbb   Xin Long   ip6_vti: support ...
1247
  vti_tunnel_ipv6_failed:
08622869e   Xin Long   ip6_vti: support ...
1248
  #endif
fa9ad96d4   Steffen Klassert   vti6: Update the ...
1249
  	xfrm6_protocol_deregister(&vti_ipcomp6_protocol, IPPROTO_COMP);
e59d82fd3   Mathias Krause   vti6: Simplify er...
1250
  xfrm_proto_comp_failed:
fa9ad96d4   Steffen Klassert   vti6: Update the ...
1251
  	xfrm6_protocol_deregister(&vti_ah6_protocol, IPPROTO_AH);
e59d82fd3   Mathias Krause   vti6: Simplify er...
1252
  xfrm_proto_ah_failed:
fa9ad96d4   Steffen Klassert   vti6: Update the ...
1253
  	xfrm6_protocol_deregister(&vti_esp6_protocol, IPPROTO_ESP);
e59d82fd3   Mathias Krause   vti6: Simplify er...
1254
  xfrm_proto_esp_failed:
ed1efb2ae   Steffen Klassert   ipv6: Add support...
1255
  	unregister_pernet_device(&vti6_net_ops);
e59d82fd3   Mathias Krause   vti6: Simplify er...
1256
1257
1258
  pernet_dev_failed:
  	pr_err("vti6 init: failed to register %s
  ", msg);
ed1efb2ae   Steffen Klassert   ipv6: Add support...
1259
1260
1261
1262
1263
1264
1265
1266
1267
  	return err;
  }
  
  /**
   * vti6_tunnel_cleanup - free resources and unregister protocol
   **/
  static void __exit vti6_tunnel_cleanup(void)
  {
  	rtnl_link_unregister(&vti6_link_ops);
96a208295   Xin Long   ip6_vti: use IS_R...
1268
  #if IS_REACHABLE(CONFIG_INET6_XFRM_TUNNEL)
a87571479   Xin Long   ip6_vti: not regi...
1269
  	xfrm6_tunnel_deregister(&vti_ip6ip_handler, AF_INET);
08622869e   Xin Long   ip6_vti: support ...
1270
1271
  	xfrm6_tunnel_deregister(&vti_ipv6_handler, AF_INET6);
  #endif
e59d82fd3   Mathias Krause   vti6: Simplify er...
1272
1273
1274
  	xfrm6_protocol_deregister(&vti_ipcomp6_protocol, IPPROTO_COMP);
  	xfrm6_protocol_deregister(&vti_ah6_protocol, IPPROTO_AH);
  	xfrm6_protocol_deregister(&vti_esp6_protocol, IPPROTO_ESP);
ed1efb2ae   Steffen Klassert   ipv6: Add support...
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
  	unregister_pernet_device(&vti6_net_ops);
  }
  
  module_init(vti6_tunnel_init);
  module_exit(vti6_tunnel_cleanup);
  MODULE_LICENSE("GPL");
  MODULE_ALIAS_RTNL_LINK("vti6");
  MODULE_ALIAS_NETDEV("ip6_vti0");
  MODULE_AUTHOR("Steffen Klassert");
  MODULE_DESCRIPTION("IPv6 virtual tunnel interface");