blob: 714b6a80361df2cb616f2682cae04c20ad463b68 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09002 * Linux NET3: GRE over IP protocol decoder.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 *
4 * Authors: Alexey Kuznetsov (kuznet@ms2.inr.ac.ru)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 */
12
Randy Dunlap4fc268d2006-01-11 12:17:47 -080013#include <linux/capability.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070014#include <linux/module.h>
15#include <linux/types.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070016#include <linux/kernel.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090017#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070018#include <asm/uaccess.h>
19#include <linux/skbuff.h>
20#include <linux/netdevice.h>
21#include <linux/in.h>
22#include <linux/tcp.h>
23#include <linux/udp.h>
24#include <linux/if_arp.h>
25#include <linux/mroute.h>
26#include <linux/init.h>
27#include <linux/in6.h>
28#include <linux/inetdevice.h>
29#include <linux/igmp.h>
30#include <linux/netfilter_ipv4.h>
Herbert Xue1a80002008-10-09 12:00:17 -070031#include <linux/etherdevice.h>
Kris Katterjohn46f25df2006-01-05 16:35:42 -080032#include <linux/if_ether.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070033
34#include <net/sock.h>
35#include <net/ip.h>
36#include <net/icmp.h>
37#include <net/protocol.h>
38#include <net/ipip.h>
39#include <net/arp.h>
40#include <net/checksum.h>
41#include <net/dsfield.h>
42#include <net/inet_ecn.h>
43#include <net/xfrm.h>
Pavel Emelyanov59a4c752008-04-16 01:08:53 -070044#include <net/net_namespace.h>
45#include <net/netns/generic.h>
Herbert Xuc19e6542008-10-09 11:59:55 -070046#include <net/rtnetlink.h>
Dmitry Kozlov00959ad2010-08-21 23:05:39 -070047#include <net/gre.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070048
49#ifdef CONFIG_IPV6
50#include <net/ipv6.h>
51#include <net/ip6_fib.h>
52#include <net/ip6_route.h>
53#endif
54
55/*
56 Problems & solutions
57 --------------------
58
59 1. The most important issue is detecting local dead loops.
60 They would cause complete host lockup in transmit, which
61 would be "resolved" by stack overflow or, if queueing is enabled,
62 with infinite looping in net_bh.
63
64 We cannot track such dead loops during route installation,
65 it is infeasible task. The most general solutions would be
66 to keep skb->encapsulation counter (sort of local ttl),
67 and silently drop packet when it expires. It is the best
68 solution, but it supposes maintaing new variable in ALL
69 skb, even if no tunneling is used.
70
Eric Dumazeta43912a2009-09-23 10:28:33 +000071 Current solution: HARD_TX_LOCK lock breaks dead loops.
Linus Torvalds1da177e2005-04-16 15:20:36 -070072
73
74
75 2. Networking dead loops would not kill routers, but would really
76 kill network. IP hop limit plays role of "t->recursion" in this case,
77 if we copy it from packet being encapsulated to upper header.
78 It is very good solution, but it introduces two problems:
79
80 - Routing protocols, using packets with ttl=1 (OSPF, RIP2),
81 do not work over tunnels.
82 - traceroute does not work. I planned to relay ICMP from tunnel,
83 so that this problem would be solved and traceroute output
84 would even more informative. This idea appeared to be wrong:
85 only Linux complies to rfc1812 now (yes, guys, Linux is the only
86 true router now :-)), all routers (at least, in neighbourhood of mine)
87 return only 8 bytes of payload. It is the end.
88
89 Hence, if we want that OSPF worked or traceroute said something reasonable,
90 we should search for another solution.
91
92 One of them is to parse packet trying to detect inner encapsulation
93 made by our node. It is difficult or even impossible, especially,
94 taking into account fragmentation. TO be short, tt is not solution at all.
95
96 Current solution: The solution was UNEXPECTEDLY SIMPLE.
97 We force DF flag on tunnels with preconfigured hop limit,
98 that is ALL. :-) Well, it does not remove the problem completely,
99 but exponential growth of network traffic is changed to linear
100 (branches, that exceed pmtu are pruned) and tunnel mtu
101 fastly degrades to value <68, where looping stops.
102 Yes, it is not good if there exists a router in the loop,
103 which does not force DF, even when encapsulating packets have DF set.
104 But it is not our problem! Nobody could accuse us, we made
105 all that we could make. Even if it is your gated who injected
106 fatal route to network, even if it were you who configured
107 fatal static route: you are innocent. :-)
108
109
110
111 3. Really, ipv4/ipip.c, ipv4/ip_gre.c and ipv6/sit.c contain
112 practically identical code. It would be good to glue them
113 together, but it is not very evident, how to make them modular.
114 sit is integral part of IPv6, ipip and gre are naturally modular.
115 We could extract common parts (hash table, ioctl etc)
116 to a separate module (ip_tunnel.c).
117
118 Alexey Kuznetsov.
119 */
120
Herbert Xuc19e6542008-10-09 11:59:55 -0700121static struct rtnl_link_ops ipgre_link_ops __read_mostly;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122static int ipgre_tunnel_init(struct net_device *dev);
123static void ipgre_tunnel_setup(struct net_device *dev);
Herbert Xu42aa9162008-10-09 11:59:32 -0700124static int ipgre_tunnel_bind_dev(struct net_device *dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125
126/* Fallback tunnel: no source, no destination, no key, no options */
127
Pavel Emelyanoveb8ce742008-04-16 01:10:26 -0700128#define HASH_SIZE 16
129
Eric Dumazetf99189b2009-11-17 10:42:49 +0000130static int ipgre_net_id __read_mostly;
Pavel Emelyanov59a4c752008-04-16 01:08:53 -0700131struct ipgre_net {
Eric Dumazet15078502010-09-15 11:07:53 +0000132 struct ip_tunnel __rcu *tunnels[4][HASH_SIZE];
Pavel Emelyanoveb8ce742008-04-16 01:10:26 -0700133
Pavel Emelyanov7daa0002008-04-16 01:10:05 -0700134 struct net_device *fb_tunnel_dev;
Pavel Emelyanov59a4c752008-04-16 01:08:53 -0700135};
136
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137/* Tunnel hash table */
138
139/*
140 4 hash tables:
141
142 3: (remote,local)
143 2: (remote,*)
144 1: (*,local)
145 0: (*,*)
146
147 We require exact key match i.e. if a key is present in packet
148 it will match only tunnel with the same key; if it is not present,
149 it will match only keyless tunnel.
150
151 All keysless packets, if not matched configured keyless tunnels
152 will match fallback tunnel.
153 */
154
Al Virod5a0a1e2006-11-08 00:23:14 -0800155#define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156
Pavel Emelyanoveb8ce742008-04-16 01:10:26 -0700157#define tunnels_r_l tunnels[3]
158#define tunnels_r tunnels[2]
159#define tunnels_l tunnels[1]
160#define tunnels_wc tunnels[0]
Eric Dumazet8d5b2c02009-10-23 06:14:38 +0000161/*
Eric Dumazet15078502010-09-15 11:07:53 +0000162 * Locking : hash tables are protected by RCU and RTNL
Eric Dumazet8d5b2c02009-10-23 06:14:38 +0000163 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164
Eric Dumazet8d5b2c02009-10-23 06:14:38 +0000165#define for_each_ip_tunnel_rcu(start) \
166 for (t = rcu_dereference(start); t; t = rcu_dereference(t->next))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167
168/* Given src, dst and key, find appropriate for input tunnel. */
169
Timo Teras749c10f2009-01-19 17:22:12 -0800170static struct ip_tunnel * ipgre_tunnel_lookup(struct net_device *dev,
Herbert Xue1a80002008-10-09 12:00:17 -0700171 __be32 remote, __be32 local,
172 __be32 key, __be16 gre_proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173{
Timo Teras749c10f2009-01-19 17:22:12 -0800174 struct net *net = dev_net(dev);
175 int link = dev->ifindex;
Eric Dumazet15078502010-09-15 11:07:53 +0000176 unsigned int h0 = HASH(remote);
177 unsigned int h1 = HASH(key);
Timo Terasafcf1242009-01-26 20:56:10 -0800178 struct ip_tunnel *t, *cand = NULL;
Pavel Emelyanov7daa0002008-04-16 01:10:05 -0700179 struct ipgre_net *ign = net_generic(net, ipgre_net_id);
Herbert Xue1a80002008-10-09 12:00:17 -0700180 int dev_type = (gre_proto == htons(ETH_P_TEB)) ?
181 ARPHRD_ETHER : ARPHRD_IPGRE;
Timo Terasafcf1242009-01-26 20:56:10 -0800182 int score, cand_score = 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183
Eric Dumazet8d5b2c02009-10-23 06:14:38 +0000184 for_each_ip_tunnel_rcu(ign->tunnels_r_l[h0 ^ h1]) {
Timo Teras749c10f2009-01-19 17:22:12 -0800185 if (local != t->parms.iph.saddr ||
186 remote != t->parms.iph.daddr ||
187 key != t->parms.i_key ||
188 !(t->dev->flags & IFF_UP))
189 continue;
190
191 if (t->dev->type != ARPHRD_IPGRE &&
192 t->dev->type != dev_type)
193 continue;
194
Timo Terasafcf1242009-01-26 20:56:10 -0800195 score = 0;
Timo Teras749c10f2009-01-19 17:22:12 -0800196 if (t->parms.link != link)
Timo Terasafcf1242009-01-26 20:56:10 -0800197 score |= 1;
Timo Teras749c10f2009-01-19 17:22:12 -0800198 if (t->dev->type != dev_type)
Timo Terasafcf1242009-01-26 20:56:10 -0800199 score |= 2;
200 if (score == 0)
Timo Teras749c10f2009-01-19 17:22:12 -0800201 return t;
Timo Terasafcf1242009-01-26 20:56:10 -0800202
203 if (score < cand_score) {
204 cand = t;
205 cand_score = score;
206 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207 }
Herbert Xue1a80002008-10-09 12:00:17 -0700208
Eric Dumazet8d5b2c02009-10-23 06:14:38 +0000209 for_each_ip_tunnel_rcu(ign->tunnels_r[h0 ^ h1]) {
Timo Teras749c10f2009-01-19 17:22:12 -0800210 if (remote != t->parms.iph.daddr ||
211 key != t->parms.i_key ||
212 !(t->dev->flags & IFF_UP))
213 continue;
214
215 if (t->dev->type != ARPHRD_IPGRE &&
216 t->dev->type != dev_type)
217 continue;
218
Timo Terasafcf1242009-01-26 20:56:10 -0800219 score = 0;
Timo Teras749c10f2009-01-19 17:22:12 -0800220 if (t->parms.link != link)
Timo Terasafcf1242009-01-26 20:56:10 -0800221 score |= 1;
Timo Teras749c10f2009-01-19 17:22:12 -0800222 if (t->dev->type != dev_type)
Timo Terasafcf1242009-01-26 20:56:10 -0800223 score |= 2;
224 if (score == 0)
Timo Teras749c10f2009-01-19 17:22:12 -0800225 return t;
Timo Terasafcf1242009-01-26 20:56:10 -0800226
227 if (score < cand_score) {
228 cand = t;
229 cand_score = score;
230 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231 }
Herbert Xue1a80002008-10-09 12:00:17 -0700232
Eric Dumazet8d5b2c02009-10-23 06:14:38 +0000233 for_each_ip_tunnel_rcu(ign->tunnels_l[h1]) {
Timo Teras749c10f2009-01-19 17:22:12 -0800234 if ((local != t->parms.iph.saddr &&
235 (local != t->parms.iph.daddr ||
236 !ipv4_is_multicast(local))) ||
237 key != t->parms.i_key ||
238 !(t->dev->flags & IFF_UP))
239 continue;
240
241 if (t->dev->type != ARPHRD_IPGRE &&
242 t->dev->type != dev_type)
243 continue;
244
Timo Terasafcf1242009-01-26 20:56:10 -0800245 score = 0;
Timo Teras749c10f2009-01-19 17:22:12 -0800246 if (t->parms.link != link)
Timo Terasafcf1242009-01-26 20:56:10 -0800247 score |= 1;
Timo Teras749c10f2009-01-19 17:22:12 -0800248 if (t->dev->type != dev_type)
Timo Terasafcf1242009-01-26 20:56:10 -0800249 score |= 2;
250 if (score == 0)
Timo Teras749c10f2009-01-19 17:22:12 -0800251 return t;
Timo Terasafcf1242009-01-26 20:56:10 -0800252
253 if (score < cand_score) {
254 cand = t;
255 cand_score = score;
256 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257 }
Herbert Xue1a80002008-10-09 12:00:17 -0700258
Eric Dumazet8d5b2c02009-10-23 06:14:38 +0000259 for_each_ip_tunnel_rcu(ign->tunnels_wc[h1]) {
Timo Teras749c10f2009-01-19 17:22:12 -0800260 if (t->parms.i_key != key ||
261 !(t->dev->flags & IFF_UP))
262 continue;
263
264 if (t->dev->type != ARPHRD_IPGRE &&
265 t->dev->type != dev_type)
266 continue;
267
Timo Terasafcf1242009-01-26 20:56:10 -0800268 score = 0;
Timo Teras749c10f2009-01-19 17:22:12 -0800269 if (t->parms.link != link)
Timo Terasafcf1242009-01-26 20:56:10 -0800270 score |= 1;
Timo Teras749c10f2009-01-19 17:22:12 -0800271 if (t->dev->type != dev_type)
Timo Terasafcf1242009-01-26 20:56:10 -0800272 score |= 2;
273 if (score == 0)
Timo Teras749c10f2009-01-19 17:22:12 -0800274 return t;
Timo Terasafcf1242009-01-26 20:56:10 -0800275
276 if (score < cand_score) {
277 cand = t;
278 cand_score = score;
279 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 }
281
Timo Terasafcf1242009-01-26 20:56:10 -0800282 if (cand != NULL)
283 return cand;
Herbert Xue1a80002008-10-09 12:00:17 -0700284
Eric Dumazet8d5b2c02009-10-23 06:14:38 +0000285 dev = ign->fb_tunnel_dev;
286 if (dev->flags & IFF_UP)
287 return netdev_priv(dev);
Timo Teras749c10f2009-01-19 17:22:12 -0800288
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 return NULL;
290}
291
Eric Dumazet15078502010-09-15 11:07:53 +0000292static struct ip_tunnel __rcu **__ipgre_bucket(struct ipgre_net *ign,
Pavel Emelyanovf57e7d52008-04-16 01:09:22 -0700293 struct ip_tunnel_parm *parms)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294{
YOSHIFUJI Hideaki5056a1e2007-04-24 20:44:48 +0900295 __be32 remote = parms->iph.daddr;
296 __be32 local = parms->iph.saddr;
297 __be32 key = parms->i_key;
Eric Dumazet15078502010-09-15 11:07:53 +0000298 unsigned int h = HASH(key);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 int prio = 0;
300
301 if (local)
302 prio |= 1;
Joe Perchesf97c1e02007-12-16 13:45:43 -0800303 if (remote && !ipv4_is_multicast(remote)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304 prio |= 2;
305 h ^= HASH(remote);
306 }
307
Pavel Emelyanoveb8ce742008-04-16 01:10:26 -0700308 return &ign->tunnels[prio][h];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309}
310
Eric Dumazet15078502010-09-15 11:07:53 +0000311static inline struct ip_tunnel __rcu **ipgre_bucket(struct ipgre_net *ign,
Pavel Emelyanovf57e7d52008-04-16 01:09:22 -0700312 struct ip_tunnel *t)
YOSHIFUJI Hideaki5056a1e2007-04-24 20:44:48 +0900313{
Pavel Emelyanovf57e7d52008-04-16 01:09:22 -0700314 return __ipgre_bucket(ign, &t->parms);
YOSHIFUJI Hideaki5056a1e2007-04-24 20:44:48 +0900315}
316
Pavel Emelyanovf57e7d52008-04-16 01:09:22 -0700317static void ipgre_tunnel_link(struct ipgre_net *ign, struct ip_tunnel *t)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318{
Eric Dumazet15078502010-09-15 11:07:53 +0000319 struct ip_tunnel __rcu **tp = ipgre_bucket(ign, t);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320
Eric Dumazet15078502010-09-15 11:07:53 +0000321 rcu_assign_pointer(t->next, rtnl_dereference(*tp));
Eric Dumazet8d5b2c02009-10-23 06:14:38 +0000322 rcu_assign_pointer(*tp, t);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323}
324
Pavel Emelyanovf57e7d52008-04-16 01:09:22 -0700325static void ipgre_tunnel_unlink(struct ipgre_net *ign, struct ip_tunnel *t)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326{
Eric Dumazet15078502010-09-15 11:07:53 +0000327 struct ip_tunnel __rcu **tp;
328 struct ip_tunnel *iter;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329
Eric Dumazet15078502010-09-15 11:07:53 +0000330 for (tp = ipgre_bucket(ign, t);
331 (iter = rtnl_dereference(*tp)) != NULL;
332 tp = &iter->next) {
333 if (t == iter) {
334 rcu_assign_pointer(*tp, t->next);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335 break;
336 }
337 }
338}
339
Herbert Xue1a80002008-10-09 12:00:17 -0700340static struct ip_tunnel *ipgre_tunnel_find(struct net *net,
341 struct ip_tunnel_parm *parms,
342 int type)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343{
Al Virod5a0a1e2006-11-08 00:23:14 -0800344 __be32 remote = parms->iph.daddr;
345 __be32 local = parms->iph.saddr;
346 __be32 key = parms->i_key;
Timo Teras749c10f2009-01-19 17:22:12 -0800347 int link = parms->link;
Eric Dumazet15078502010-09-15 11:07:53 +0000348 struct ip_tunnel *t;
349 struct ip_tunnel __rcu **tp;
Herbert Xue1a80002008-10-09 12:00:17 -0700350 struct ipgre_net *ign = net_generic(net, ipgre_net_id);
351
Eric Dumazet15078502010-09-15 11:07:53 +0000352 for (tp = __ipgre_bucket(ign, parms);
353 (t = rtnl_dereference(*tp)) != NULL;
354 tp = &t->next)
Herbert Xue1a80002008-10-09 12:00:17 -0700355 if (local == t->parms.iph.saddr &&
356 remote == t->parms.iph.daddr &&
357 key == t->parms.i_key &&
Timo Teras749c10f2009-01-19 17:22:12 -0800358 link == t->parms.link &&
Herbert Xue1a80002008-10-09 12:00:17 -0700359 type == t->dev->type)
360 break;
361
362 return t;
363}
364
Eric Dumazet15078502010-09-15 11:07:53 +0000365static struct ip_tunnel *ipgre_tunnel_locate(struct net *net,
Herbert Xue1a80002008-10-09 12:00:17 -0700366 struct ip_tunnel_parm *parms, int create)
367{
368 struct ip_tunnel *t, *nt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 struct net_device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 char name[IFNAMSIZ];
Pavel Emelyanovf57e7d52008-04-16 01:09:22 -0700371 struct ipgre_net *ign = net_generic(net, ipgre_net_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372
Herbert Xue1a80002008-10-09 12:00:17 -0700373 t = ipgre_tunnel_find(net, parms, ARPHRD_IPGRE);
374 if (t || !create)
375 return t;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376
377 if (parms->name[0])
378 strlcpy(name, parms->name, IFNAMSIZ);
Pavel Emelyanov34cc7ba62008-02-23 20:19:20 -0800379 else
380 sprintf(name, "gre%%d");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381
382 dev = alloc_netdev(sizeof(*t), name, ipgre_tunnel_setup);
383 if (!dev)
384 return NULL;
385
Pavel Emelyanov0b67ece2008-04-16 01:11:13 -0700386 dev_net_set(dev, net);
387
Pavel Emelyanovb37d428b2008-02-26 23:51:04 -0800388 if (strchr(name, '%')) {
389 if (dev_alloc_name(dev, name) < 0)
390 goto failed_free;
391 }
392
Patrick McHardy2941a482006-01-08 22:05:26 -0800393 nt = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 nt->parms = *parms;
Herbert Xuc19e6542008-10-09 11:59:55 -0700395 dev->rtnl_link_ops = &ipgre_link_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396
Herbert Xu42aa9162008-10-09 11:59:32 -0700397 dev->mtu = ipgre_tunnel_bind_dev(dev);
398
Pavel Emelyanovb37d428b2008-02-26 23:51:04 -0800399 if (register_netdevice(dev) < 0)
400 goto failed_free;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 dev_hold(dev);
Pavel Emelyanovf57e7d52008-04-16 01:09:22 -0700403 ipgre_tunnel_link(ign, nt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 return nt;
405
Pavel Emelyanovb37d428b2008-02-26 23:51:04 -0800406failed_free:
407 free_netdev(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 return NULL;
409}
410
411static void ipgre_tunnel_uninit(struct net_device *dev)
412{
Pavel Emelyanovf57e7d52008-04-16 01:09:22 -0700413 struct net *net = dev_net(dev);
414 struct ipgre_net *ign = net_generic(net, ipgre_net_id);
415
416 ipgre_tunnel_unlink(ign, netdev_priv(dev));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 dev_put(dev);
418}
419
420
421static void ipgre_err(struct sk_buff *skb, u32 info)
422{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423
Rami Rosen071f92d2008-05-21 17:47:54 -0700424/* All the routers (except for Linux) return only
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 8 bytes of packet payload. It means, that precise relaying of
426 ICMP in the real Internet is absolutely infeasible.
427
428 Moreover, Cisco "wise men" put GRE key to the third word
429 in GRE header. It makes impossible maintaining even soft state for keyed
430 GRE tunnels with enabled checksum. Tell them "thank you".
431
432 Well, I wonder, rfc1812 was written by Cisco employee,
433 what the hell these idiots break standrads established
434 by themself???
435 */
436
Jianjun Kong6ed25332008-11-03 00:25:16 -0800437 struct iphdr *iph = (struct iphdr *)skb->data;
Al Virod5a0a1e2006-11-08 00:23:14 -0800438 __be16 *p = (__be16*)(skb->data+(iph->ihl<<2));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 int grehlen = (iph->ihl<<2) + 4;
Arnaldo Carvalho de Melo88c76642007-03-13 14:43:18 -0300440 const int type = icmp_hdr(skb)->type;
441 const int code = icmp_hdr(skb)->code;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442 struct ip_tunnel *t;
Al Virod5a0a1e2006-11-08 00:23:14 -0800443 __be16 flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444
445 flags = p[0];
446 if (flags&(GRE_CSUM|GRE_KEY|GRE_SEQ|GRE_ROUTING|GRE_VERSION)) {
447 if (flags&(GRE_VERSION|GRE_ROUTING))
448 return;
449 if (flags&GRE_KEY) {
450 grehlen += 4;
451 if (flags&GRE_CSUM)
452 grehlen += 4;
453 }
454 }
455
456 /* If only 8 bytes returned, keyed message will be dropped here */
457 if (skb_headlen(skb) < grehlen)
458 return;
459
460 switch (type) {
461 default:
462 case ICMP_PARAMETERPROB:
463 return;
464
465 case ICMP_DEST_UNREACH:
466 switch (code) {
467 case ICMP_SR_FAILED:
468 case ICMP_PORT_UNREACH:
469 /* Impossible event. */
470 return;
471 case ICMP_FRAG_NEEDED:
472 /* Soft state for pmtu is maintained by IP core. */
473 return;
474 default:
475 /* All others are translated to HOST_UNREACH.
476 rfc2003 contains "deep thoughts" about NET_UNREACH,
477 I believe they are just ether pollution. --ANK
478 */
479 break;
480 }
481 break;
482 case ICMP_TIME_EXCEEDED:
483 if (code != ICMP_EXC_TTL)
484 return;
485 break;
486 }
487
Eric Dumazet8d5b2c02009-10-23 06:14:38 +0000488 rcu_read_lock();
Timo Teras749c10f2009-01-19 17:22:12 -0800489 t = ipgre_tunnel_lookup(skb->dev, iph->daddr, iph->saddr,
Herbert Xue1a80002008-10-09 12:00:17 -0700490 flags & GRE_KEY ?
491 *(((__be32 *)p) + (grehlen / 4) - 1) : 0,
492 p[1]);
Joe Perchesf97c1e02007-12-16 13:45:43 -0800493 if (t == NULL || t->parms.iph.daddr == 0 ||
494 ipv4_is_multicast(t->parms.iph.daddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 goto out;
496
497 if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED)
498 goto out;
499
Wei Yongjunda6185d82009-02-24 23:34:48 -0800500 if (time_before(jiffies, t->err_time + IPTUNNEL_ERR_TIMEO))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 t->err_count++;
502 else
503 t->err_count = 1;
504 t->err_time = jiffies;
505out:
Eric Dumazet8d5b2c02009-10-23 06:14:38 +0000506 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507}
508
509static inline void ipgre_ecn_decapsulate(struct iphdr *iph, struct sk_buff *skb)
510{
511 if (INET_ECN_is_ce(iph->tos)) {
512 if (skb->protocol == htons(ETH_P_IP)) {
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700513 IP_ECN_set_ce(ip_hdr(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 } else if (skb->protocol == htons(ETH_P_IPV6)) {
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700515 IP6_ECN_set_ce(ipv6_hdr(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516 }
517 }
518}
519
520static inline u8
521ipgre_ecn_encapsulate(u8 tos, struct iphdr *old_iph, struct sk_buff *skb)
522{
523 u8 inner = 0;
524 if (skb->protocol == htons(ETH_P_IP))
525 inner = old_iph->tos;
526 else if (skb->protocol == htons(ETH_P_IPV6))
527 inner = ipv6_get_dsfield((struct ipv6hdr *)old_iph);
528 return INET_ECN_encapsulate(tos, inner);
529}
530
531static int ipgre_rcv(struct sk_buff *skb)
532{
533 struct iphdr *iph;
534 u8 *h;
Al Virod5a0a1e2006-11-08 00:23:14 -0800535 __be16 flags;
Al Virod3bc23e2006-11-14 21:24:49 -0800536 __sum16 csum = 0;
Al Virod5a0a1e2006-11-08 00:23:14 -0800537 __be32 key = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 u32 seqno = 0;
539 struct ip_tunnel *tunnel;
540 int offset = 4;
Herbert Xue1a80002008-10-09 12:00:17 -0700541 __be16 gre_proto;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542
543 if (!pskb_may_pull(skb, 16))
544 goto drop_nolock;
545
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700546 iph = ip_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 h = skb->data;
Al Virod5a0a1e2006-11-08 00:23:14 -0800548 flags = *(__be16*)h;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549
550 if (flags&(GRE_CSUM|GRE_KEY|GRE_ROUTING|GRE_SEQ|GRE_VERSION)) {
551 /* - Version must be 0.
552 - We do not support routing headers.
553 */
554 if (flags&(GRE_VERSION|GRE_ROUTING))
555 goto drop_nolock;
556
557 if (flags&GRE_CSUM) {
Herbert Xufb286bb2005-11-10 13:01:24 -0800558 switch (skb->ip_summed) {
Patrick McHardy84fa7932006-08-29 16:44:56 -0700559 case CHECKSUM_COMPLETE:
Al Virod3bc23e2006-11-14 21:24:49 -0800560 csum = csum_fold(skb->csum);
Herbert Xufb286bb2005-11-10 13:01:24 -0800561 if (!csum)
562 break;
563 /* fall through */
564 case CHECKSUM_NONE:
565 skb->csum = 0;
566 csum = __skb_checksum_complete(skb);
Patrick McHardy84fa7932006-08-29 16:44:56 -0700567 skb->ip_summed = CHECKSUM_COMPLETE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568 }
569 offset += 4;
570 }
571 if (flags&GRE_KEY) {
Al Virod5a0a1e2006-11-08 00:23:14 -0800572 key = *(__be32*)(h + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 offset += 4;
574 }
575 if (flags&GRE_SEQ) {
Al Virod5a0a1e2006-11-08 00:23:14 -0800576 seqno = ntohl(*(__be32*)(h + offset));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 offset += 4;
578 }
579 }
580
Herbert Xue1a80002008-10-09 12:00:17 -0700581 gre_proto = *(__be16 *)(h + 2);
582
Eric Dumazet8d5b2c02009-10-23 06:14:38 +0000583 rcu_read_lock();
Timo Teras749c10f2009-01-19 17:22:12 -0800584 if ((tunnel = ipgre_tunnel_lookup(skb->dev,
Herbert Xue1a80002008-10-09 12:00:17 -0700585 iph->saddr, iph->daddr, key,
586 gre_proto))) {
Pavel Emelyanovaddd68e2008-05-21 14:14:22 -0700587 struct net_device_stats *stats = &tunnel->dev->stats;
588
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589 secpath_reset(skb);
590
Herbert Xue1a80002008-10-09 12:00:17 -0700591 skb->protocol = gre_proto;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592 /* WCCP version 1 and 2 protocol decoding.
593 * - Change protocol to IP
594 * - When dealing with WCCPv2, Skip extra 4 bytes in GRE header
595 */
Herbert Xue1a80002008-10-09 12:00:17 -0700596 if (flags == 0 && gre_proto == htons(ETH_P_WCCP)) {
YOSHIFUJI Hideaki496c98d2006-10-10 19:41:21 -0700597 skb->protocol = htons(ETH_P_IP);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900598 if ((*(h + offset) & 0xF0) != 0x40)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 offset += 4;
600 }
601
Timo Teras1d069162007-12-20 00:10:33 -0800602 skb->mac_header = skb->network_header;
Arnaldo Carvalho de Melo4209fb62007-03-10 18:42:03 -0300603 __pskb_pull(skb, offset);
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -0700604 skb_postpull_rcsum(skb, skb_transport_header(skb), offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605 skb->pkt_type = PACKET_HOST;
606#ifdef CONFIG_NET_IPGRE_BROADCAST
Joe Perchesf97c1e02007-12-16 13:45:43 -0800607 if (ipv4_is_multicast(iph->daddr)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608 /* Looped back packet, drop it! */
Eric Dumazet511c3f92009-06-02 05:14:27 +0000609 if (skb_rtable(skb)->fl.iif == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 goto drop;
Pavel Emelyanovaddd68e2008-05-21 14:14:22 -0700611 stats->multicast++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 skb->pkt_type = PACKET_BROADCAST;
613 }
614#endif
615
616 if (((flags&GRE_CSUM) && csum) ||
617 (!(flags&GRE_CSUM) && tunnel->parms.i_flags&GRE_CSUM)) {
Pavel Emelyanovaddd68e2008-05-21 14:14:22 -0700618 stats->rx_crc_errors++;
619 stats->rx_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620 goto drop;
621 }
622 if (tunnel->parms.i_flags&GRE_SEQ) {
623 if (!(flags&GRE_SEQ) ||
624 (tunnel->i_seqno && (s32)(seqno - tunnel->i_seqno) < 0)) {
Pavel Emelyanovaddd68e2008-05-21 14:14:22 -0700625 stats->rx_fifo_errors++;
626 stats->rx_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 goto drop;
628 }
629 tunnel->i_seqno = seqno + 1;
630 }
Herbert Xue1a80002008-10-09 12:00:17 -0700631
632 /* Warning: All skb pointers will be invalidated! */
633 if (tunnel->dev->type == ARPHRD_ETHER) {
634 if (!pskb_may_pull(skb, ETH_HLEN)) {
635 stats->rx_length_errors++;
636 stats->rx_errors++;
637 goto drop;
638 }
639
640 iph = ip_hdr(skb);
641 skb->protocol = eth_type_trans(skb, tunnel->dev);
642 skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN);
643 }
644
Eric Dumazetd19d56d2010-05-17 22:36:55 -0700645 skb_tunnel_rx(skb, tunnel->dev);
Herbert Xue1a80002008-10-09 12:00:17 -0700646
647 skb_reset_network_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 ipgre_ecn_decapsulate(iph, skb);
Herbert Xue1a80002008-10-09 12:00:17 -0700649
Eric Dumazet8990f462010-09-20 00:12:11 +0000650 if (netif_rx(skb) == NET_RX_DROP)
651 stats->rx_dropped++;
652
Eric Dumazet8d5b2c02009-10-23 06:14:38 +0000653 rcu_read_unlock();
Eric Dumazet8990f462010-09-20 00:12:11 +0000654 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 }
Herbert Xu45af08b2006-04-05 22:31:19 -0700656 icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657
658drop:
Eric Dumazet8d5b2c02009-10-23 06:14:38 +0000659 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660drop_nolock:
661 kfree_skb(skb);
662 return(0);
663}
664
Stephen Hemminger6fef4c02009-08-31 19:50:41 +0000665static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666{
Patrick McHardy2941a482006-01-08 22:05:26 -0800667 struct ip_tunnel *tunnel = netdev_priv(dev);
Eric Dumazet0bfbedb2009-10-05 00:11:22 -0700668 struct net_device_stats *stats = &dev->stats;
669 struct netdev_queue *txq = netdev_get_tx_queue(dev, 0);
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700670 struct iphdr *old_iph = ip_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 struct iphdr *tiph;
672 u8 tos;
Al Virod5a0a1e2006-11-08 00:23:14 -0800673 __be16 df;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 struct rtable *rt; /* Route to the other host */
Eric Dumazet15078502010-09-15 11:07:53 +0000675 struct net_device *tdev; /* Device to other host */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 struct iphdr *iph; /* Our new IP header */
Chuck Leverc2636b42007-10-23 21:07:32 -0700677 unsigned int max_headroom; /* The extra header space needed */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678 int gre_hlen;
Al Virod5a0a1e2006-11-08 00:23:14 -0800679 __be32 dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 int mtu;
681
Herbert Xue1a80002008-10-09 12:00:17 -0700682 if (dev->type == ARPHRD_ETHER)
683 IPCB(skb)->flags = 0;
684
685 if (dev->header_ops && dev->type == ARPHRD_IPGRE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 gre_hlen = 0;
Jianjun Kong6ed25332008-11-03 00:25:16 -0800687 tiph = (struct iphdr *)skb->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 } else {
689 gre_hlen = tunnel->hlen;
690 tiph = &tunnel->parms.iph;
691 }
692
693 if ((dst = tiph->daddr) == 0) {
694 /* NBMA tunnel */
695
Eric Dumazetadf30902009-06-02 05:19:30 +0000696 if (skb_dst(skb) == NULL) {
Pavel Emelyanovaddd68e2008-05-21 14:14:22 -0700697 stats->tx_fifo_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 goto tx_error;
699 }
700
701 if (skb->protocol == htons(ETH_P_IP)) {
Eric Dumazet511c3f92009-06-02 05:14:27 +0000702 rt = skb_rtable(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 if ((dst = rt->rt_gateway) == 0)
704 goto tx_error_icmp;
705 }
706#ifdef CONFIG_IPV6
707 else if (skb->protocol == htons(ETH_P_IPV6)) {
708 struct in6_addr *addr6;
709 int addr_type;
Eric Dumazetadf30902009-06-02 05:19:30 +0000710 struct neighbour *neigh = skb_dst(skb)->neighbour;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711
712 if (neigh == NULL)
713 goto tx_error;
714
Jianjun Kong6ed25332008-11-03 00:25:16 -0800715 addr6 = (struct in6_addr *)&neigh->primary_key;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 addr_type = ipv6_addr_type(addr6);
717
718 if (addr_type == IPV6_ADDR_ANY) {
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700719 addr6 = &ipv6_hdr(skb)->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 addr_type = ipv6_addr_type(addr6);
721 }
722
723 if ((addr_type & IPV6_ADDR_COMPATv4) == 0)
724 goto tx_error_icmp;
725
726 dst = addr6->s6_addr32[3];
727 }
728#endif
729 else
730 goto tx_error;
731 }
732
733 tos = tiph->tos;
Andreas Jaggiee686ca2009-07-14 09:35:59 -0700734 if (tos == 1) {
735 tos = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 if (skb->protocol == htons(ETH_P_IP))
737 tos = old_iph->tos;
Stephen Hemmingerdd4ba832010-07-08 21:35:58 -0700738 else if (skb->protocol == htons(ETH_P_IPV6))
739 tos = ipv6_get_dsfield((struct ipv6hdr *)old_iph);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 }
741
742 {
743 struct flowi fl = { .oif = tunnel->parms.link,
744 .nl_u = { .ip4_u =
745 { .daddr = dst,
746 .saddr = tiph->saddr,
747 .tos = RT_TOS(tos) } },
748 .proto = IPPROTO_GRE };
Pavel Emelyanov96635522008-04-16 01:10:44 -0700749 if (ip_route_output_key(dev_net(dev), &rt, &fl)) {
Pavel Emelyanovaddd68e2008-05-21 14:14:22 -0700750 stats->tx_carrier_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 goto tx_error;
752 }
753 }
Changli Gaod8d1f302010-06-10 23:31:35 -0700754 tdev = rt->dst.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755
756 if (tdev == dev) {
757 ip_rt_put(rt);
Pavel Emelyanovaddd68e2008-05-21 14:14:22 -0700758 stats->collisions++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 goto tx_error;
760 }
761
762 df = tiph->frag_off;
763 if (df)
Changli Gaod8d1f302010-06-10 23:31:35 -0700764 mtu = dst_mtu(&rt->dst) - dev->hard_header_len - tunnel->hlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765 else
Eric Dumazetadf30902009-06-02 05:19:30 +0000766 mtu = skb_dst(skb) ? dst_mtu(skb_dst(skb)) : dev->mtu;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767
Eric Dumazetadf30902009-06-02 05:19:30 +0000768 if (skb_dst(skb))
769 skb_dst(skb)->ops->update_pmtu(skb_dst(skb), mtu);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770
771 if (skb->protocol == htons(ETH_P_IP)) {
772 df |= (old_iph->frag_off&htons(IP_DF));
773
774 if ((old_iph->frag_off&htons(IP_DF)) &&
775 mtu < ntohs(old_iph->tot_len)) {
776 icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));
777 ip_rt_put(rt);
778 goto tx_error;
779 }
780 }
781#ifdef CONFIG_IPV6
782 else if (skb->protocol == htons(ETH_P_IPV6)) {
Eric Dumazetadf30902009-06-02 05:19:30 +0000783 struct rt6_info *rt6 = (struct rt6_info *)skb_dst(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784
Eric Dumazetadf30902009-06-02 05:19:30 +0000785 if (rt6 && mtu < dst_mtu(skb_dst(skb)) && mtu >= IPV6_MIN_MTU) {
Joe Perchesf97c1e02007-12-16 13:45:43 -0800786 if ((tunnel->parms.iph.daddr &&
787 !ipv4_is_multicast(tunnel->parms.iph.daddr)) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 rt6->rt6i_dst.plen == 128) {
789 rt6->rt6i_flags |= RTF_MODIFIED;
Eric Dumazetadf30902009-06-02 05:19:30 +0000790 skb_dst(skb)->metrics[RTAX_MTU-1] = mtu;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 }
792 }
793
794 if (mtu >= IPV6_MIN_MTU && mtu < skb->len - tunnel->hlen + gre_hlen) {
Alexey Dobriyan3ffe5332010-02-18 08:25:24 +0000795 icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 ip_rt_put(rt);
797 goto tx_error;
798 }
799 }
800#endif
801
802 if (tunnel->err_count > 0) {
Wei Yongjunda6185d82009-02-24 23:34:48 -0800803 if (time_before(jiffies,
804 tunnel->err_time + IPTUNNEL_ERR_TIMEO)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 tunnel->err_count--;
806
807 dst_link_failure(skb);
808 } else
809 tunnel->err_count = 0;
810 }
811
Changli Gaod8d1f302010-06-10 23:31:35 -0700812 max_headroom = LL_RESERVED_SPACE(tdev) + gre_hlen + rt->dst.header_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813
Patrick McHardycfbba492007-07-09 15:33:40 -0700814 if (skb_headroom(skb) < max_headroom || skb_shared(skb)||
815 (skb_cloned(skb) && !skb_clone_writable(skb, 0))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom);
Timo Teräs243aad82010-03-20 02:27:58 +0000817 if (max_headroom > dev->needed_headroom)
818 dev->needed_headroom = max_headroom;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819 if (!new_skb) {
820 ip_rt_put(rt);
Eric Dumazet0bfbedb2009-10-05 00:11:22 -0700821 txq->tx_dropped++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 dev_kfree_skb(skb);
Patrick McHardy6ed10652009-06-23 06:03:08 +0000823 return NETDEV_TX_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 }
825 if (skb->sk)
826 skb_set_owner_w(new_skb, skb->sk);
827 dev_kfree_skb(skb);
828 skb = new_skb;
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700829 old_iph = ip_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 }
831
Herbert Xu64194c32008-10-09 12:03:17 -0700832 skb_reset_transport_header(skb);
Arnaldo Carvalho de Meloe2d1bca2007-04-10 20:46:21 -0700833 skb_push(skb, gre_hlen);
834 skb_reset_network_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
Patrick McHardy48d5cad2006-02-15 15:10:22 -0800836 IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED |
837 IPSKB_REROUTED);
Eric Dumazetadf30902009-06-02 05:19:30 +0000838 skb_dst_drop(skb);
Changli Gaod8d1f302010-06-10 23:31:35 -0700839 skb_dst_set(skb, &rt->dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840
841 /*
842 * Push down and install the IPIP header.
843 */
844
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700845 iph = ip_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 iph->version = 4;
847 iph->ihl = sizeof(struct iphdr) >> 2;
848 iph->frag_off = df;
849 iph->protocol = IPPROTO_GRE;
850 iph->tos = ipgre_ecn_encapsulate(tos, old_iph, skb);
851 iph->daddr = rt->rt_dst;
852 iph->saddr = rt->rt_src;
853
854 if ((iph->ttl = tiph->ttl) == 0) {
855 if (skb->protocol == htons(ETH_P_IP))
856 iph->ttl = old_iph->ttl;
857#ifdef CONFIG_IPV6
858 else if (skb->protocol == htons(ETH_P_IPV6))
Jianjun Kong6ed25332008-11-03 00:25:16 -0800859 iph->ttl = ((struct ipv6hdr *)old_iph)->hop_limit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860#endif
861 else
Changli Gaod8d1f302010-06-10 23:31:35 -0700862 iph->ttl = dst_metric(&rt->dst, RTAX_HOPLIMIT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 }
864
Herbert Xue1a80002008-10-09 12:00:17 -0700865 ((__be16 *)(iph + 1))[0] = tunnel->parms.o_flags;
866 ((__be16 *)(iph + 1))[1] = (dev->type == ARPHRD_ETHER) ?
867 htons(ETH_P_TEB) : skb->protocol;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868
869 if (tunnel->parms.o_flags&(GRE_KEY|GRE_CSUM|GRE_SEQ)) {
Al Virod5a0a1e2006-11-08 00:23:14 -0800870 __be32 *ptr = (__be32*)(((u8*)iph) + tunnel->hlen - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871
872 if (tunnel->parms.o_flags&GRE_SEQ) {
873 ++tunnel->o_seqno;
874 *ptr = htonl(tunnel->o_seqno);
875 ptr--;
876 }
877 if (tunnel->parms.o_flags&GRE_KEY) {
878 *ptr = tunnel->parms.o_key;
879 ptr--;
880 }
881 if (tunnel->parms.o_flags&GRE_CSUM) {
882 *ptr = 0;
Al Viro5f92a732006-11-14 21:36:54 -0800883 *(__sum16*)ptr = ip_compute_csum((void*)(iph+1), skb->len - sizeof(struct iphdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884 }
885 }
886
887 nf_reset(skb);
888
889 IPTUNNEL_XMIT();
Patrick McHardy6ed10652009-06-23 06:03:08 +0000890 return NETDEV_TX_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891
892tx_error_icmp:
893 dst_link_failure(skb);
894
895tx_error:
896 stats->tx_errors++;
897 dev_kfree_skb(skb);
Patrick McHardy6ed10652009-06-23 06:03:08 +0000898 return NETDEV_TX_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899}
900
Herbert Xu42aa9162008-10-09 11:59:32 -0700901static int ipgre_tunnel_bind_dev(struct net_device *dev)
Michal Schmidtee34c1e2007-12-13 09:46:32 -0800902{
903 struct net_device *tdev = NULL;
904 struct ip_tunnel *tunnel;
905 struct iphdr *iph;
906 int hlen = LL_MAX_HEADER;
907 int mtu = ETH_DATA_LEN;
908 int addend = sizeof(struct iphdr) + 4;
909
910 tunnel = netdev_priv(dev);
911 iph = &tunnel->parms.iph;
912
Herbert Xuc95b8192008-10-09 11:58:54 -0700913 /* Guess output device to choose reasonable mtu and needed_headroom */
Michal Schmidtee34c1e2007-12-13 09:46:32 -0800914
915 if (iph->daddr) {
916 struct flowi fl = { .oif = tunnel->parms.link,
917 .nl_u = { .ip4_u =
918 { .daddr = iph->daddr,
919 .saddr = iph->saddr,
920 .tos = RT_TOS(iph->tos) } },
921 .proto = IPPROTO_GRE };
922 struct rtable *rt;
Pavel Emelyanov96635522008-04-16 01:10:44 -0700923 if (!ip_route_output_key(dev_net(dev), &rt, &fl)) {
Changli Gaod8d1f302010-06-10 23:31:35 -0700924 tdev = rt->dst.dev;
Michal Schmidtee34c1e2007-12-13 09:46:32 -0800925 ip_rt_put(rt);
926 }
Herbert Xue1a80002008-10-09 12:00:17 -0700927
928 if (dev->type != ARPHRD_ETHER)
929 dev->flags |= IFF_POINTOPOINT;
Michal Schmidtee34c1e2007-12-13 09:46:32 -0800930 }
931
932 if (!tdev && tunnel->parms.link)
Pavel Emelyanov96635522008-04-16 01:10:44 -0700933 tdev = __dev_get_by_index(dev_net(dev), tunnel->parms.link);
Michal Schmidtee34c1e2007-12-13 09:46:32 -0800934
935 if (tdev) {
Herbert Xuc95b8192008-10-09 11:58:54 -0700936 hlen = tdev->hard_header_len + tdev->needed_headroom;
Michal Schmidtee34c1e2007-12-13 09:46:32 -0800937 mtu = tdev->mtu;
938 }
939 dev->iflink = tunnel->parms.link;
940
941 /* Precalculate GRE options length */
942 if (tunnel->parms.o_flags&(GRE_CSUM|GRE_KEY|GRE_SEQ)) {
943 if (tunnel->parms.o_flags&GRE_CSUM)
944 addend += 4;
945 if (tunnel->parms.o_flags&GRE_KEY)
946 addend += 4;
947 if (tunnel->parms.o_flags&GRE_SEQ)
948 addend += 4;
949 }
Herbert Xuc95b8192008-10-09 11:58:54 -0700950 dev->needed_headroom = addend + hlen;
Tom Goff8cdb0452009-08-14 16:33:56 -0700951 mtu -= dev->hard_header_len + addend;
Herbert Xu42aa9162008-10-09 11:59:32 -0700952
953 if (mtu < 68)
954 mtu = 68;
955
Michal Schmidtee34c1e2007-12-13 09:46:32 -0800956 tunnel->hlen = addend;
957
Herbert Xu42aa9162008-10-09 11:59:32 -0700958 return mtu;
Michal Schmidtee34c1e2007-12-13 09:46:32 -0800959}
960
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961static int
962ipgre_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
963{
964 int err = 0;
965 struct ip_tunnel_parm p;
966 struct ip_tunnel *t;
Pavel Emelyanovf57e7d52008-04-16 01:09:22 -0700967 struct net *net = dev_net(dev);
968 struct ipgre_net *ign = net_generic(net, ipgre_net_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969
970 switch (cmd) {
971 case SIOCGETTUNNEL:
972 t = NULL;
Pavel Emelyanov7daa0002008-04-16 01:10:05 -0700973 if (dev == ign->fb_tunnel_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974 if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) {
975 err = -EFAULT;
976 break;
977 }
Pavel Emelyanovf57e7d52008-04-16 01:09:22 -0700978 t = ipgre_tunnel_locate(net, &p, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 }
980 if (t == NULL)
Patrick McHardy2941a482006-01-08 22:05:26 -0800981 t = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 memcpy(&p, &t->parms, sizeof(p));
983 if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p)))
984 err = -EFAULT;
985 break;
986
987 case SIOCADDTUNNEL:
988 case SIOCCHGTUNNEL:
989 err = -EPERM;
990 if (!capable(CAP_NET_ADMIN))
991 goto done;
992
993 err = -EFAULT;
994 if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
995 goto done;
996
997 err = -EINVAL;
998 if (p.iph.version != 4 || p.iph.protocol != IPPROTO_GRE ||
999 p.iph.ihl != 5 || (p.iph.frag_off&htons(~IP_DF)) ||
1000 ((p.i_flags|p.o_flags)&(GRE_VERSION|GRE_ROUTING)))
1001 goto done;
1002 if (p.iph.ttl)
1003 p.iph.frag_off |= htons(IP_DF);
1004
1005 if (!(p.i_flags&GRE_KEY))
1006 p.i_key = 0;
1007 if (!(p.o_flags&GRE_KEY))
1008 p.o_key = 0;
1009
Pavel Emelyanovf57e7d52008-04-16 01:09:22 -07001010 t = ipgre_tunnel_locate(net, &p, cmd == SIOCADDTUNNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011
Pavel Emelyanov7daa0002008-04-16 01:10:05 -07001012 if (dev != ign->fb_tunnel_dev && cmd == SIOCCHGTUNNEL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013 if (t != NULL) {
1014 if (t->dev != dev) {
1015 err = -EEXIST;
1016 break;
1017 }
1018 } else {
Eric Dumazet15078502010-09-15 11:07:53 +00001019 unsigned int nflags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020
Patrick McHardy2941a482006-01-08 22:05:26 -08001021 t = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022
Joe Perchesf97c1e02007-12-16 13:45:43 -08001023 if (ipv4_is_multicast(p.iph.daddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024 nflags = IFF_BROADCAST;
1025 else if (p.iph.daddr)
1026 nflags = IFF_POINTOPOINT;
1027
1028 if ((dev->flags^nflags)&(IFF_POINTOPOINT|IFF_BROADCAST)) {
1029 err = -EINVAL;
1030 break;
1031 }
Pavel Emelyanovf57e7d52008-04-16 01:09:22 -07001032 ipgre_tunnel_unlink(ign, t);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033 t->parms.iph.saddr = p.iph.saddr;
1034 t->parms.iph.daddr = p.iph.daddr;
1035 t->parms.i_key = p.i_key;
1036 t->parms.o_key = p.o_key;
1037 memcpy(dev->dev_addr, &p.iph.saddr, 4);
1038 memcpy(dev->broadcast, &p.iph.daddr, 4);
Pavel Emelyanovf57e7d52008-04-16 01:09:22 -07001039 ipgre_tunnel_link(ign, t);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040 netdev_state_change(dev);
1041 }
1042 }
1043
1044 if (t) {
1045 err = 0;
1046 if (cmd == SIOCCHGTUNNEL) {
1047 t->parms.iph.ttl = p.iph.ttl;
1048 t->parms.iph.tos = p.iph.tos;
1049 t->parms.iph.frag_off = p.iph.frag_off;
Michal Schmidtee34c1e2007-12-13 09:46:32 -08001050 if (t->parms.link != p.link) {
1051 t->parms.link = p.link;
Herbert Xu42aa9162008-10-09 11:59:32 -07001052 dev->mtu = ipgre_tunnel_bind_dev(dev);
Michal Schmidtee34c1e2007-12-13 09:46:32 -08001053 netdev_state_change(dev);
1054 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055 }
1056 if (copy_to_user(ifr->ifr_ifru.ifru_data, &t->parms, sizeof(p)))
1057 err = -EFAULT;
1058 } else
1059 err = (cmd == SIOCADDTUNNEL ? -ENOBUFS : -ENOENT);
1060 break;
1061
1062 case SIOCDELTUNNEL:
1063 err = -EPERM;
1064 if (!capable(CAP_NET_ADMIN))
1065 goto done;
1066
Pavel Emelyanov7daa0002008-04-16 01:10:05 -07001067 if (dev == ign->fb_tunnel_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068 err = -EFAULT;
1069 if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
1070 goto done;
1071 err = -ENOENT;
Pavel Emelyanovf57e7d52008-04-16 01:09:22 -07001072 if ((t = ipgre_tunnel_locate(net, &p, 0)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073 goto done;
1074 err = -EPERM;
Pavel Emelyanov7daa0002008-04-16 01:10:05 -07001075 if (t == netdev_priv(ign->fb_tunnel_dev))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076 goto done;
1077 dev = t->dev;
1078 }
Stephen Hemminger22f8cde2007-02-07 00:09:58 -08001079 unregister_netdevice(dev);
1080 err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081 break;
1082
1083 default:
1084 err = -EINVAL;
1085 }
1086
1087done:
1088 return err;
1089}
1090
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091static int ipgre_tunnel_change_mtu(struct net_device *dev, int new_mtu)
1092{
Patrick McHardy2941a482006-01-08 22:05:26 -08001093 struct ip_tunnel *tunnel = netdev_priv(dev);
Herbert Xuc95b8192008-10-09 11:58:54 -07001094 if (new_mtu < 68 ||
1095 new_mtu > 0xFFF8 - dev->hard_header_len - tunnel->hlen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 return -EINVAL;
1097 dev->mtu = new_mtu;
1098 return 0;
1099}
1100
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101/* Nice toy. Unfortunately, useless in real life :-)
1102 It allows to construct virtual multiprotocol broadcast "LAN"
1103 over the Internet, provided multicast routing is tuned.
1104
1105
1106 I have no idea was this bicycle invented before me,
1107 so that I had to set ARPHRD_IPGRE to a random value.
1108 I have an impression, that Cisco could make something similar,
1109 but this feature is apparently missing in IOS<=11.2(8).
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001110
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111 I set up 10.66.66/24 and fec0:6666:6666::0/96 as virtual networks
1112 with broadcast 224.66.66.66. If you have access to mbone, play with me :-)
1113
1114 ping -t 255 224.66.66.66
1115
1116 If nobody answers, mbone does not work.
1117
1118 ip tunnel add Universe mode gre remote 224.66.66.66 local <Your_real_addr> ttl 255
1119 ip addr add 10.66.66.<somewhat>/24 dev Universe
1120 ifconfig Universe up
1121 ifconfig Universe add fe80::<Your_real_addr>/10
1122 ifconfig Universe add fec0:6666:6666::<Your_real_addr>/96
1123 ftp 10.66.66.66
1124 ...
1125 ftp fec0:6666:6666::193.233.7.65
1126 ...
1127
1128 */
1129
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -07001130static int ipgre_header(struct sk_buff *skb, struct net_device *dev,
1131 unsigned short type,
Eric Dumazet15078502010-09-15 11:07:53 +00001132 const void *daddr, const void *saddr, unsigned int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133{
Patrick McHardy2941a482006-01-08 22:05:26 -08001134 struct ip_tunnel *t = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135 struct iphdr *iph = (struct iphdr *)skb_push(skb, t->hlen);
Al Virod5a0a1e2006-11-08 00:23:14 -08001136 __be16 *p = (__be16*)(iph+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137
1138 memcpy(iph, &t->parms.iph, sizeof(struct iphdr));
1139 p[0] = t->parms.o_flags;
1140 p[1] = htons(type);
1141
1142 /*
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001143 * Set the source hardware address.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144 */
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001145
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146 if (saddr)
1147 memcpy(&iph->saddr, saddr, 4);
Timo Teräs6d55cb92010-03-03 04:01:13 +00001148 if (daddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149 memcpy(&iph->daddr, daddr, 4);
Timo Teräs6d55cb92010-03-03 04:01:13 +00001150 if (iph->daddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151 return t->hlen;
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001152
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 return -t->hlen;
1154}
1155
Timo Teras6a5f44d2007-10-23 20:31:53 -07001156static int ipgre_header_parse(const struct sk_buff *skb, unsigned char *haddr)
1157{
Jianjun Kong6ed25332008-11-03 00:25:16 -08001158 struct iphdr *iph = (struct iphdr *) skb_mac_header(skb);
Timo Teras6a5f44d2007-10-23 20:31:53 -07001159 memcpy(haddr, &iph->saddr, 4);
1160 return 4;
1161}
1162
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -07001163static const struct header_ops ipgre_header_ops = {
1164 .create = ipgre_header,
Timo Teras6a5f44d2007-10-23 20:31:53 -07001165 .parse = ipgre_header_parse,
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -07001166};
1167
Timo Teras6a5f44d2007-10-23 20:31:53 -07001168#ifdef CONFIG_NET_IPGRE_BROADCAST
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169static int ipgre_open(struct net_device *dev)
1170{
Patrick McHardy2941a482006-01-08 22:05:26 -08001171 struct ip_tunnel *t = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172
Joe Perchesf97c1e02007-12-16 13:45:43 -08001173 if (ipv4_is_multicast(t->parms.iph.daddr)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174 struct flowi fl = { .oif = t->parms.link,
1175 .nl_u = { .ip4_u =
1176 { .daddr = t->parms.iph.daddr,
1177 .saddr = t->parms.iph.saddr,
1178 .tos = RT_TOS(t->parms.iph.tos) } },
1179 .proto = IPPROTO_GRE };
1180 struct rtable *rt;
Pavel Emelyanov96635522008-04-16 01:10:44 -07001181 if (ip_route_output_key(dev_net(dev), &rt, &fl))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182 return -EADDRNOTAVAIL;
Changli Gaod8d1f302010-06-10 23:31:35 -07001183 dev = rt->dst.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 ip_rt_put(rt);
Herbert Xue5ed6392005-10-03 14:35:55 -07001185 if (__in_dev_get_rtnl(dev) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186 return -EADDRNOTAVAIL;
1187 t->mlink = dev->ifindex;
Herbert Xue5ed6392005-10-03 14:35:55 -07001188 ip_mc_inc_group(__in_dev_get_rtnl(dev), t->parms.iph.daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189 }
1190 return 0;
1191}
1192
1193static int ipgre_close(struct net_device *dev)
1194{
Patrick McHardy2941a482006-01-08 22:05:26 -08001195 struct ip_tunnel *t = netdev_priv(dev);
Stephen Hemmingerb8c26a32008-11-20 20:34:29 -08001196
Joe Perchesf97c1e02007-12-16 13:45:43 -08001197 if (ipv4_is_multicast(t->parms.iph.daddr) && t->mlink) {
Denis V. Lunev7fee0ca2008-01-21 17:32:38 -08001198 struct in_device *in_dev;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001199 in_dev = inetdev_by_index(dev_net(dev), t->mlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200 if (in_dev) {
1201 ip_mc_dec_group(in_dev, t->parms.iph.daddr);
1202 in_dev_put(in_dev);
1203 }
1204 }
1205 return 0;
1206}
1207
1208#endif
1209
Stephen Hemmingerb8c26a32008-11-20 20:34:29 -08001210static const struct net_device_ops ipgre_netdev_ops = {
1211 .ndo_init = ipgre_tunnel_init,
1212 .ndo_uninit = ipgre_tunnel_uninit,
1213#ifdef CONFIG_NET_IPGRE_BROADCAST
1214 .ndo_open = ipgre_open,
1215 .ndo_stop = ipgre_close,
1216#endif
1217 .ndo_start_xmit = ipgre_tunnel_xmit,
1218 .ndo_do_ioctl = ipgre_tunnel_ioctl,
1219 .ndo_change_mtu = ipgre_tunnel_change_mtu,
1220};
1221
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222static void ipgre_tunnel_setup(struct net_device *dev)
1223{
Stephen Hemmingerb8c26a32008-11-20 20:34:29 -08001224 dev->netdev_ops = &ipgre_netdev_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225 dev->destructor = free_netdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226
1227 dev->type = ARPHRD_IPGRE;
Herbert Xuc95b8192008-10-09 11:58:54 -07001228 dev->needed_headroom = LL_MAX_HEADER + sizeof(struct iphdr) + 4;
Kris Katterjohn46f25df2006-01-05 16:35:42 -08001229 dev->mtu = ETH_DATA_LEN - sizeof(struct iphdr) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230 dev->flags = IFF_NOARP;
1231 dev->iflink = 0;
1232 dev->addr_len = 4;
Pavel Emelyanov0b67ece2008-04-16 01:11:13 -07001233 dev->features |= NETIF_F_NETNS_LOCAL;
Eric Dumazet108bfa82009-05-28 22:35:10 +00001234 dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235}
1236
1237static int ipgre_tunnel_init(struct net_device *dev)
1238{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 struct ip_tunnel *tunnel;
1240 struct iphdr *iph;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241
Patrick McHardy2941a482006-01-08 22:05:26 -08001242 tunnel = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243 iph = &tunnel->parms.iph;
1244
1245 tunnel->dev = dev;
1246 strcpy(tunnel->parms.name, dev->name);
1247
1248 memcpy(dev->dev_addr, &tunnel->parms.iph.saddr, 4);
1249 memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4);
1250
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251 if (iph->daddr) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252#ifdef CONFIG_NET_IPGRE_BROADCAST
Joe Perchesf97c1e02007-12-16 13:45:43 -08001253 if (ipv4_is_multicast(iph->daddr)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254 if (!iph->saddr)
1255 return -EINVAL;
1256 dev->flags = IFF_BROADCAST;
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -07001257 dev->header_ops = &ipgre_header_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258 }
1259#endif
Michal Schmidtee34c1e2007-12-13 09:46:32 -08001260 } else
Timo Teras6a5f44d2007-10-23 20:31:53 -07001261 dev->header_ops = &ipgre_header_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263 return 0;
1264}
1265
Stephen Hemmingerb8c26a32008-11-20 20:34:29 -08001266static void ipgre_fb_tunnel_init(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001267{
Patrick McHardy2941a482006-01-08 22:05:26 -08001268 struct ip_tunnel *tunnel = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269 struct iphdr *iph = &tunnel->parms.iph;
Pavel Emelyanoveb8ce742008-04-16 01:10:26 -07001270 struct ipgre_net *ign = net_generic(dev_net(dev), ipgre_net_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001271
1272 tunnel->dev = dev;
1273 strcpy(tunnel->parms.name, dev->name);
1274
1275 iph->version = 4;
1276 iph->protocol = IPPROTO_GRE;
1277 iph->ihl = 5;
1278 tunnel->hlen = sizeof(struct iphdr) + 4;
1279
1280 dev_hold(dev);
Eric Dumazet15078502010-09-15 11:07:53 +00001281 rcu_assign_pointer(ign->tunnels_wc[0], tunnel);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282}
1283
1284
Dmitry Kozlov00959ad2010-08-21 23:05:39 -07001285static const struct gre_protocol ipgre_protocol = {
1286 .handler = ipgre_rcv,
1287 .err_handler = ipgre_err,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288};
1289
Eric Dumazeteef6dd62009-10-27 07:07:16 +00001290static void ipgre_destroy_tunnels(struct ipgre_net *ign, struct list_head *head)
Pavel Emelyanoveb8ce742008-04-16 01:10:26 -07001291{
1292 int prio;
1293
1294 for (prio = 0; prio < 4; prio++) {
1295 int h;
1296 for (h = 0; h < HASH_SIZE; h++) {
Eric Dumazet15078502010-09-15 11:07:53 +00001297 struct ip_tunnel *t;
1298
1299 t = rtnl_dereference(ign->tunnels[prio][h]);
Eric Dumazeteef6dd62009-10-27 07:07:16 +00001300
1301 while (t != NULL) {
1302 unregister_netdevice_queue(t->dev, head);
Eric Dumazet15078502010-09-15 11:07:53 +00001303 t = rtnl_dereference(t->next);
Eric Dumazeteef6dd62009-10-27 07:07:16 +00001304 }
Pavel Emelyanoveb8ce742008-04-16 01:10:26 -07001305 }
1306 }
1307}
1308
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00001309static int __net_init ipgre_init_net(struct net *net)
Pavel Emelyanov59a4c752008-04-16 01:08:53 -07001310{
Eric W. Biedermancfb8fbf2009-11-29 15:46:13 +00001311 struct ipgre_net *ign = net_generic(net, ipgre_net_id);
Pavel Emelyanov59a4c752008-04-16 01:08:53 -07001312 int err;
Pavel Emelyanov59a4c752008-04-16 01:08:53 -07001313
Pavel Emelyanov7daa0002008-04-16 01:10:05 -07001314 ign->fb_tunnel_dev = alloc_netdev(sizeof(struct ip_tunnel), "gre0",
1315 ipgre_tunnel_setup);
1316 if (!ign->fb_tunnel_dev) {
1317 err = -ENOMEM;
1318 goto err_alloc_dev;
1319 }
Alexey Dobriyanbe77e592008-11-23 17:26:26 -08001320 dev_net_set(ign->fb_tunnel_dev, net);
Pavel Emelyanov7daa0002008-04-16 01:10:05 -07001321
Stephen Hemmingerb8c26a32008-11-20 20:34:29 -08001322 ipgre_fb_tunnel_init(ign->fb_tunnel_dev);
Herbert Xuc19e6542008-10-09 11:59:55 -07001323 ign->fb_tunnel_dev->rtnl_link_ops = &ipgre_link_ops;
Pavel Emelyanov7daa0002008-04-16 01:10:05 -07001324
1325 if ((err = register_netdev(ign->fb_tunnel_dev)))
1326 goto err_reg_dev;
1327
Pavel Emelyanov59a4c752008-04-16 01:08:53 -07001328 return 0;
1329
Pavel Emelyanov7daa0002008-04-16 01:10:05 -07001330err_reg_dev:
1331 free_netdev(ign->fb_tunnel_dev);
1332err_alloc_dev:
Pavel Emelyanov59a4c752008-04-16 01:08:53 -07001333 return err;
1334}
1335
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00001336static void __net_exit ipgre_exit_net(struct net *net)
Pavel Emelyanov59a4c752008-04-16 01:08:53 -07001337{
1338 struct ipgre_net *ign;
Eric Dumazeteef6dd62009-10-27 07:07:16 +00001339 LIST_HEAD(list);
Pavel Emelyanov59a4c752008-04-16 01:08:53 -07001340
1341 ign = net_generic(net, ipgre_net_id);
Pavel Emelyanov7daa0002008-04-16 01:10:05 -07001342 rtnl_lock();
Eric Dumazeteef6dd62009-10-27 07:07:16 +00001343 ipgre_destroy_tunnels(ign, &list);
1344 unregister_netdevice_many(&list);
Pavel Emelyanov7daa0002008-04-16 01:10:05 -07001345 rtnl_unlock();
Pavel Emelyanov59a4c752008-04-16 01:08:53 -07001346}
1347
1348static struct pernet_operations ipgre_net_ops = {
1349 .init = ipgre_init_net,
1350 .exit = ipgre_exit_net,
Eric W. Biedermancfb8fbf2009-11-29 15:46:13 +00001351 .id = &ipgre_net_id,
1352 .size = sizeof(struct ipgre_net),
Pavel Emelyanov59a4c752008-04-16 01:08:53 -07001353};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354
Herbert Xuc19e6542008-10-09 11:59:55 -07001355static int ipgre_tunnel_validate(struct nlattr *tb[], struct nlattr *data[])
1356{
1357 __be16 flags;
1358
1359 if (!data)
1360 return 0;
1361
1362 flags = 0;
1363 if (data[IFLA_GRE_IFLAGS])
1364 flags |= nla_get_be16(data[IFLA_GRE_IFLAGS]);
1365 if (data[IFLA_GRE_OFLAGS])
1366 flags |= nla_get_be16(data[IFLA_GRE_OFLAGS]);
1367 if (flags & (GRE_VERSION|GRE_ROUTING))
1368 return -EINVAL;
1369
1370 return 0;
1371}
1372
Herbert Xue1a80002008-10-09 12:00:17 -07001373static int ipgre_tap_validate(struct nlattr *tb[], struct nlattr *data[])
1374{
1375 __be32 daddr;
1376
1377 if (tb[IFLA_ADDRESS]) {
1378 if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN)
1379 return -EINVAL;
1380 if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS])))
1381 return -EADDRNOTAVAIL;
1382 }
1383
1384 if (!data)
1385 goto out;
1386
1387 if (data[IFLA_GRE_REMOTE]) {
1388 memcpy(&daddr, nla_data(data[IFLA_GRE_REMOTE]), 4);
1389 if (!daddr)
1390 return -EINVAL;
1391 }
1392
1393out:
1394 return ipgre_tunnel_validate(tb, data);
1395}
1396
Herbert Xuc19e6542008-10-09 11:59:55 -07001397static void ipgre_netlink_parms(struct nlattr *data[],
1398 struct ip_tunnel_parm *parms)
1399{
Herbert Xu7bb82d922008-10-11 12:20:15 -07001400 memset(parms, 0, sizeof(*parms));
Herbert Xuc19e6542008-10-09 11:59:55 -07001401
1402 parms->iph.protocol = IPPROTO_GRE;
1403
1404 if (!data)
1405 return;
1406
1407 if (data[IFLA_GRE_LINK])
1408 parms->link = nla_get_u32(data[IFLA_GRE_LINK]);
1409
1410 if (data[IFLA_GRE_IFLAGS])
1411 parms->i_flags = nla_get_be16(data[IFLA_GRE_IFLAGS]);
1412
1413 if (data[IFLA_GRE_OFLAGS])
1414 parms->o_flags = nla_get_be16(data[IFLA_GRE_OFLAGS]);
1415
1416 if (data[IFLA_GRE_IKEY])
1417 parms->i_key = nla_get_be32(data[IFLA_GRE_IKEY]);
1418
1419 if (data[IFLA_GRE_OKEY])
1420 parms->o_key = nla_get_be32(data[IFLA_GRE_OKEY]);
1421
1422 if (data[IFLA_GRE_LOCAL])
Patrick McHardy4d74f8b2008-10-10 12:11:06 -07001423 parms->iph.saddr = nla_get_be32(data[IFLA_GRE_LOCAL]);
Herbert Xuc19e6542008-10-09 11:59:55 -07001424
1425 if (data[IFLA_GRE_REMOTE])
Patrick McHardy4d74f8b2008-10-10 12:11:06 -07001426 parms->iph.daddr = nla_get_be32(data[IFLA_GRE_REMOTE]);
Herbert Xuc19e6542008-10-09 11:59:55 -07001427
1428 if (data[IFLA_GRE_TTL])
1429 parms->iph.ttl = nla_get_u8(data[IFLA_GRE_TTL]);
1430
1431 if (data[IFLA_GRE_TOS])
1432 parms->iph.tos = nla_get_u8(data[IFLA_GRE_TOS]);
1433
1434 if (!data[IFLA_GRE_PMTUDISC] || nla_get_u8(data[IFLA_GRE_PMTUDISC]))
1435 parms->iph.frag_off = htons(IP_DF);
1436}
1437
Herbert Xue1a80002008-10-09 12:00:17 -07001438static int ipgre_tap_init(struct net_device *dev)
1439{
1440 struct ip_tunnel *tunnel;
1441
1442 tunnel = netdev_priv(dev);
1443
1444 tunnel->dev = dev;
1445 strcpy(tunnel->parms.name, dev->name);
1446
1447 ipgre_tunnel_bind_dev(dev);
1448
1449 return 0;
1450}
1451
Stephen Hemmingerb8c26a32008-11-20 20:34:29 -08001452static const struct net_device_ops ipgre_tap_netdev_ops = {
1453 .ndo_init = ipgre_tap_init,
1454 .ndo_uninit = ipgre_tunnel_uninit,
1455 .ndo_start_xmit = ipgre_tunnel_xmit,
1456 .ndo_set_mac_address = eth_mac_addr,
1457 .ndo_validate_addr = eth_validate_addr,
1458 .ndo_change_mtu = ipgre_tunnel_change_mtu,
1459};
1460
Herbert Xue1a80002008-10-09 12:00:17 -07001461static void ipgre_tap_setup(struct net_device *dev)
1462{
1463
1464 ether_setup(dev);
1465
Herbert Xu2e9526b2009-10-30 05:51:48 +00001466 dev->netdev_ops = &ipgre_tap_netdev_ops;
Herbert Xue1a80002008-10-09 12:00:17 -07001467 dev->destructor = free_netdev;
Herbert Xue1a80002008-10-09 12:00:17 -07001468
1469 dev->iflink = 0;
1470 dev->features |= NETIF_F_NETNS_LOCAL;
1471}
1472
Eric W. Biederman81adee42009-11-08 00:53:51 -08001473static int ipgre_newlink(struct net *src_net, struct net_device *dev, struct nlattr *tb[],
Herbert Xuc19e6542008-10-09 11:59:55 -07001474 struct nlattr *data[])
1475{
1476 struct ip_tunnel *nt;
1477 struct net *net = dev_net(dev);
1478 struct ipgre_net *ign = net_generic(net, ipgre_net_id);
1479 int mtu;
1480 int err;
1481
1482 nt = netdev_priv(dev);
1483 ipgre_netlink_parms(data, &nt->parms);
1484
Herbert Xue1a80002008-10-09 12:00:17 -07001485 if (ipgre_tunnel_find(net, &nt->parms, dev->type))
Herbert Xuc19e6542008-10-09 11:59:55 -07001486 return -EEXIST;
1487
Herbert Xue1a80002008-10-09 12:00:17 -07001488 if (dev->type == ARPHRD_ETHER && !tb[IFLA_ADDRESS])
1489 random_ether_addr(dev->dev_addr);
1490
Herbert Xuc19e6542008-10-09 11:59:55 -07001491 mtu = ipgre_tunnel_bind_dev(dev);
1492 if (!tb[IFLA_MTU])
1493 dev->mtu = mtu;
1494
1495 err = register_netdevice(dev);
1496 if (err)
1497 goto out;
1498
1499 dev_hold(dev);
1500 ipgre_tunnel_link(ign, nt);
1501
1502out:
1503 return err;
1504}
1505
1506static int ipgre_changelink(struct net_device *dev, struct nlattr *tb[],
1507 struct nlattr *data[])
1508{
1509 struct ip_tunnel *t, *nt;
1510 struct net *net = dev_net(dev);
1511 struct ipgre_net *ign = net_generic(net, ipgre_net_id);
1512 struct ip_tunnel_parm p;
1513 int mtu;
1514
1515 if (dev == ign->fb_tunnel_dev)
1516 return -EINVAL;
1517
1518 nt = netdev_priv(dev);
1519 ipgre_netlink_parms(data, &p);
1520
1521 t = ipgre_tunnel_locate(net, &p, 0);
1522
1523 if (t) {
1524 if (t->dev != dev)
1525 return -EEXIST;
1526 } else {
Herbert Xuc19e6542008-10-09 11:59:55 -07001527 t = nt;
1528
Herbert Xu2e9526b2009-10-30 05:51:48 +00001529 if (dev->type != ARPHRD_ETHER) {
Eric Dumazet15078502010-09-15 11:07:53 +00001530 unsigned int nflags = 0;
Herbert Xuc19e6542008-10-09 11:59:55 -07001531
Herbert Xu2e9526b2009-10-30 05:51:48 +00001532 if (ipv4_is_multicast(p.iph.daddr))
1533 nflags = IFF_BROADCAST;
1534 else if (p.iph.daddr)
1535 nflags = IFF_POINTOPOINT;
1536
1537 if ((dev->flags ^ nflags) &
1538 (IFF_POINTOPOINT | IFF_BROADCAST))
1539 return -EINVAL;
1540 }
Herbert Xuc19e6542008-10-09 11:59:55 -07001541
1542 ipgre_tunnel_unlink(ign, t);
1543 t->parms.iph.saddr = p.iph.saddr;
1544 t->parms.iph.daddr = p.iph.daddr;
1545 t->parms.i_key = p.i_key;
Herbert Xu2e9526b2009-10-30 05:51:48 +00001546 if (dev->type != ARPHRD_ETHER) {
1547 memcpy(dev->dev_addr, &p.iph.saddr, 4);
1548 memcpy(dev->broadcast, &p.iph.daddr, 4);
1549 }
Herbert Xuc19e6542008-10-09 11:59:55 -07001550 ipgre_tunnel_link(ign, t);
1551 netdev_state_change(dev);
1552 }
1553
1554 t->parms.o_key = p.o_key;
1555 t->parms.iph.ttl = p.iph.ttl;
1556 t->parms.iph.tos = p.iph.tos;
1557 t->parms.iph.frag_off = p.iph.frag_off;
1558
1559 if (t->parms.link != p.link) {
1560 t->parms.link = p.link;
1561 mtu = ipgre_tunnel_bind_dev(dev);
1562 if (!tb[IFLA_MTU])
1563 dev->mtu = mtu;
1564 netdev_state_change(dev);
1565 }
1566
1567 return 0;
1568}
1569
1570static size_t ipgre_get_size(const struct net_device *dev)
1571{
1572 return
1573 /* IFLA_GRE_LINK */
1574 nla_total_size(4) +
1575 /* IFLA_GRE_IFLAGS */
1576 nla_total_size(2) +
1577 /* IFLA_GRE_OFLAGS */
1578 nla_total_size(2) +
1579 /* IFLA_GRE_IKEY */
1580 nla_total_size(4) +
1581 /* IFLA_GRE_OKEY */
1582 nla_total_size(4) +
1583 /* IFLA_GRE_LOCAL */
1584 nla_total_size(4) +
1585 /* IFLA_GRE_REMOTE */
1586 nla_total_size(4) +
1587 /* IFLA_GRE_TTL */
1588 nla_total_size(1) +
1589 /* IFLA_GRE_TOS */
1590 nla_total_size(1) +
1591 /* IFLA_GRE_PMTUDISC */
1592 nla_total_size(1) +
1593 0;
1594}
1595
1596static int ipgre_fill_info(struct sk_buff *skb, const struct net_device *dev)
1597{
1598 struct ip_tunnel *t = netdev_priv(dev);
1599 struct ip_tunnel_parm *p = &t->parms;
1600
1601 NLA_PUT_U32(skb, IFLA_GRE_LINK, p->link);
1602 NLA_PUT_BE16(skb, IFLA_GRE_IFLAGS, p->i_flags);
1603 NLA_PUT_BE16(skb, IFLA_GRE_OFLAGS, p->o_flags);
Patrick McHardyba9e64b2008-10-10 12:10:30 -07001604 NLA_PUT_BE32(skb, IFLA_GRE_IKEY, p->i_key);
1605 NLA_PUT_BE32(skb, IFLA_GRE_OKEY, p->o_key);
Patrick McHardy4d74f8b2008-10-10 12:11:06 -07001606 NLA_PUT_BE32(skb, IFLA_GRE_LOCAL, p->iph.saddr);
1607 NLA_PUT_BE32(skb, IFLA_GRE_REMOTE, p->iph.daddr);
Herbert Xuc19e6542008-10-09 11:59:55 -07001608 NLA_PUT_U8(skb, IFLA_GRE_TTL, p->iph.ttl);
1609 NLA_PUT_U8(skb, IFLA_GRE_TOS, p->iph.tos);
1610 NLA_PUT_U8(skb, IFLA_GRE_PMTUDISC, !!(p->iph.frag_off & htons(IP_DF)));
1611
1612 return 0;
1613
1614nla_put_failure:
1615 return -EMSGSIZE;
1616}
1617
1618static const struct nla_policy ipgre_policy[IFLA_GRE_MAX + 1] = {
1619 [IFLA_GRE_LINK] = { .type = NLA_U32 },
1620 [IFLA_GRE_IFLAGS] = { .type = NLA_U16 },
1621 [IFLA_GRE_OFLAGS] = { .type = NLA_U16 },
1622 [IFLA_GRE_IKEY] = { .type = NLA_U32 },
1623 [IFLA_GRE_OKEY] = { .type = NLA_U32 },
Patrick McHardy4d74f8b2008-10-10 12:11:06 -07001624 [IFLA_GRE_LOCAL] = { .len = FIELD_SIZEOF(struct iphdr, saddr) },
1625 [IFLA_GRE_REMOTE] = { .len = FIELD_SIZEOF(struct iphdr, daddr) },
Herbert Xuc19e6542008-10-09 11:59:55 -07001626 [IFLA_GRE_TTL] = { .type = NLA_U8 },
1627 [IFLA_GRE_TOS] = { .type = NLA_U8 },
1628 [IFLA_GRE_PMTUDISC] = { .type = NLA_U8 },
1629};
1630
1631static struct rtnl_link_ops ipgre_link_ops __read_mostly = {
1632 .kind = "gre",
1633 .maxtype = IFLA_GRE_MAX,
1634 .policy = ipgre_policy,
1635 .priv_size = sizeof(struct ip_tunnel),
1636 .setup = ipgre_tunnel_setup,
1637 .validate = ipgre_tunnel_validate,
1638 .newlink = ipgre_newlink,
1639 .changelink = ipgre_changelink,
1640 .get_size = ipgre_get_size,
1641 .fill_info = ipgre_fill_info,
1642};
1643
Herbert Xue1a80002008-10-09 12:00:17 -07001644static struct rtnl_link_ops ipgre_tap_ops __read_mostly = {
1645 .kind = "gretap",
1646 .maxtype = IFLA_GRE_MAX,
1647 .policy = ipgre_policy,
1648 .priv_size = sizeof(struct ip_tunnel),
1649 .setup = ipgre_tap_setup,
1650 .validate = ipgre_tap_validate,
1651 .newlink = ipgre_newlink,
1652 .changelink = ipgre_changelink,
1653 .get_size = ipgre_get_size,
1654 .fill_info = ipgre_fill_info,
1655};
1656
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657/*
1658 * And now the modules code and kernel interface.
1659 */
1660
1661static int __init ipgre_init(void)
1662{
1663 int err;
1664
1665 printk(KERN_INFO "GRE over IPv4 tunneling driver\n");
1666
Eric W. Biedermancfb8fbf2009-11-29 15:46:13 +00001667 err = register_pernet_device(&ipgre_net_ops);
Pavel Emelyanov59a4c752008-04-16 01:08:53 -07001668 if (err < 0)
Alexey Dobriyanc2892f02010-02-16 07:57:44 +00001669 return err;
1670
Dmitry Kozlov00959ad2010-08-21 23:05:39 -07001671 err = gre_add_protocol(&ipgre_protocol, GREPROTO_CISCO);
Alexey Dobriyanc2892f02010-02-16 07:57:44 +00001672 if (err < 0) {
1673 printk(KERN_INFO "ipgre init: can't add protocol\n");
1674 goto add_proto_failed;
1675 }
Pavel Emelyanov7daa0002008-04-16 01:10:05 -07001676
Herbert Xuc19e6542008-10-09 11:59:55 -07001677 err = rtnl_link_register(&ipgre_link_ops);
1678 if (err < 0)
1679 goto rtnl_link_failed;
1680
Herbert Xue1a80002008-10-09 12:00:17 -07001681 err = rtnl_link_register(&ipgre_tap_ops);
1682 if (err < 0)
1683 goto tap_ops_failed;
1684
Herbert Xuc19e6542008-10-09 11:59:55 -07001685out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686 return err;
Herbert Xuc19e6542008-10-09 11:59:55 -07001687
Herbert Xue1a80002008-10-09 12:00:17 -07001688tap_ops_failed:
1689 rtnl_link_unregister(&ipgre_link_ops);
Herbert Xuc19e6542008-10-09 11:59:55 -07001690rtnl_link_failed:
Dmitry Kozlov00959ad2010-08-21 23:05:39 -07001691 gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO);
Alexey Dobriyanc2892f02010-02-16 07:57:44 +00001692add_proto_failed:
1693 unregister_pernet_device(&ipgre_net_ops);
Herbert Xuc19e6542008-10-09 11:59:55 -07001694 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695}
1696
Alexey Kuznetsovdb445752005-07-30 17:46:44 -07001697static void __exit ipgre_fini(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698{
Herbert Xue1a80002008-10-09 12:00:17 -07001699 rtnl_link_unregister(&ipgre_tap_ops);
Herbert Xuc19e6542008-10-09 11:59:55 -07001700 rtnl_link_unregister(&ipgre_link_ops);
Dmitry Kozlov00959ad2010-08-21 23:05:39 -07001701 if (gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO) < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702 printk(KERN_INFO "ipgre close: can't remove protocol\n");
Alexey Dobriyanc2892f02010-02-16 07:57:44 +00001703 unregister_pernet_device(&ipgre_net_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704}
1705
1706module_init(ipgre_init);
1707module_exit(ipgre_fini);
1708MODULE_LICENSE("GPL");
Patrick McHardy4d74f8b2008-10-10 12:11:06 -07001709MODULE_ALIAS_RTNL_LINK("gre");
1710MODULE_ALIAS_RTNL_LINK("gretap");