blob: fc20e687e933ba2557ab36bd1a3c57d8a9374d7f [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 Emelyanov34cc7ba2008-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
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 netif_rx(skb);
Eric Dumazet8d5b2c02009-10-23 06:14:38 +0000651 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 return(0);
653 }
Herbert Xu45af08b2006-04-05 22:31:19 -0700654 icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655
656drop:
Eric Dumazet8d5b2c02009-10-23 06:14:38 +0000657 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658drop_nolock:
659 kfree_skb(skb);
660 return(0);
661}
662
Stephen Hemminger6fef4c02009-08-31 19:50:41 +0000663static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664{
Patrick McHardy2941a482006-01-08 22:05:26 -0800665 struct ip_tunnel *tunnel = netdev_priv(dev);
Eric Dumazet0bfbedb2009-10-05 00:11:22 -0700666 struct net_device_stats *stats = &dev->stats;
667 struct netdev_queue *txq = netdev_get_tx_queue(dev, 0);
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700668 struct iphdr *old_iph = ip_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 struct iphdr *tiph;
670 u8 tos;
Al Virod5a0a1e2006-11-08 00:23:14 -0800671 __be16 df;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 struct rtable *rt; /* Route to the other host */
Eric Dumazet15078502010-09-15 11:07:53 +0000673 struct net_device *tdev; /* Device to other host */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 struct iphdr *iph; /* Our new IP header */
Chuck Leverc2636b42007-10-23 21:07:32 -0700675 unsigned int max_headroom; /* The extra header space needed */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 int gre_hlen;
Al Virod5a0a1e2006-11-08 00:23:14 -0800677 __be32 dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678 int mtu;
679
Herbert Xue1a80002008-10-09 12:00:17 -0700680 if (dev->type == ARPHRD_ETHER)
681 IPCB(skb)->flags = 0;
682
683 if (dev->header_ops && dev->type == ARPHRD_IPGRE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 gre_hlen = 0;
Jianjun Kong6ed25332008-11-03 00:25:16 -0800685 tiph = (struct iphdr *)skb->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 } else {
687 gre_hlen = tunnel->hlen;
688 tiph = &tunnel->parms.iph;
689 }
690
691 if ((dst = tiph->daddr) == 0) {
692 /* NBMA tunnel */
693
Eric Dumazetadf30902009-06-02 05:19:30 +0000694 if (skb_dst(skb) == NULL) {
Pavel Emelyanovaddd68e2008-05-21 14:14:22 -0700695 stats->tx_fifo_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 goto tx_error;
697 }
698
699 if (skb->protocol == htons(ETH_P_IP)) {
Eric Dumazet511c3f92009-06-02 05:14:27 +0000700 rt = skb_rtable(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701 if ((dst = rt->rt_gateway) == 0)
702 goto tx_error_icmp;
703 }
704#ifdef CONFIG_IPV6
705 else if (skb->protocol == htons(ETH_P_IPV6)) {
706 struct in6_addr *addr6;
707 int addr_type;
Eric Dumazetadf30902009-06-02 05:19:30 +0000708 struct neighbour *neigh = skb_dst(skb)->neighbour;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709
710 if (neigh == NULL)
711 goto tx_error;
712
Jianjun Kong6ed25332008-11-03 00:25:16 -0800713 addr6 = (struct in6_addr *)&neigh->primary_key;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 addr_type = ipv6_addr_type(addr6);
715
716 if (addr_type == IPV6_ADDR_ANY) {
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700717 addr6 = &ipv6_hdr(skb)->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 addr_type = ipv6_addr_type(addr6);
719 }
720
721 if ((addr_type & IPV6_ADDR_COMPATv4) == 0)
722 goto tx_error_icmp;
723
724 dst = addr6->s6_addr32[3];
725 }
726#endif
727 else
728 goto tx_error;
729 }
730
731 tos = tiph->tos;
Andreas Jaggiee686ca2009-07-14 09:35:59 -0700732 if (tos == 1) {
733 tos = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 if (skb->protocol == htons(ETH_P_IP))
735 tos = old_iph->tos;
Stephen Hemmingerdd4ba832010-07-08 21:35:58 -0700736 else if (skb->protocol == htons(ETH_P_IPV6))
737 tos = ipv6_get_dsfield((struct ipv6hdr *)old_iph);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 }
739
740 {
741 struct flowi fl = { .oif = tunnel->parms.link,
742 .nl_u = { .ip4_u =
743 { .daddr = dst,
744 .saddr = tiph->saddr,
745 .tos = RT_TOS(tos) } },
746 .proto = IPPROTO_GRE };
Pavel Emelyanov96635522008-04-16 01:10:44 -0700747 if (ip_route_output_key(dev_net(dev), &rt, &fl)) {
Pavel Emelyanovaddd68e2008-05-21 14:14:22 -0700748 stats->tx_carrier_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749 goto tx_error;
750 }
751 }
Changli Gaod8d1f302010-06-10 23:31:35 -0700752 tdev = rt->dst.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753
754 if (tdev == dev) {
755 ip_rt_put(rt);
Pavel Emelyanovaddd68e2008-05-21 14:14:22 -0700756 stats->collisions++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 goto tx_error;
758 }
759
760 df = tiph->frag_off;
761 if (df)
Changli Gaod8d1f302010-06-10 23:31:35 -0700762 mtu = dst_mtu(&rt->dst) - dev->hard_header_len - tunnel->hlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 else
Eric Dumazetadf30902009-06-02 05:19:30 +0000764 mtu = skb_dst(skb) ? dst_mtu(skb_dst(skb)) : dev->mtu;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765
Eric Dumazetadf30902009-06-02 05:19:30 +0000766 if (skb_dst(skb))
767 skb_dst(skb)->ops->update_pmtu(skb_dst(skb), mtu);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768
769 if (skb->protocol == htons(ETH_P_IP)) {
770 df |= (old_iph->frag_off&htons(IP_DF));
771
772 if ((old_iph->frag_off&htons(IP_DF)) &&
773 mtu < ntohs(old_iph->tot_len)) {
774 icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));
775 ip_rt_put(rt);
776 goto tx_error;
777 }
778 }
779#ifdef CONFIG_IPV6
780 else if (skb->protocol == htons(ETH_P_IPV6)) {
Eric Dumazetadf30902009-06-02 05:19:30 +0000781 struct rt6_info *rt6 = (struct rt6_info *)skb_dst(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782
Eric Dumazetadf30902009-06-02 05:19:30 +0000783 if (rt6 && mtu < dst_mtu(skb_dst(skb)) && mtu >= IPV6_MIN_MTU) {
Joe Perchesf97c1e02007-12-16 13:45:43 -0800784 if ((tunnel->parms.iph.daddr &&
785 !ipv4_is_multicast(tunnel->parms.iph.daddr)) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 rt6->rt6i_dst.plen == 128) {
787 rt6->rt6i_flags |= RTF_MODIFIED;
Eric Dumazetadf30902009-06-02 05:19:30 +0000788 skb_dst(skb)->metrics[RTAX_MTU-1] = mtu;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 }
790 }
791
792 if (mtu >= IPV6_MIN_MTU && mtu < skb->len - tunnel->hlen + gre_hlen) {
Alexey Dobriyan3ffe5332010-02-18 08:25:24 +0000793 icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794 ip_rt_put(rt);
795 goto tx_error;
796 }
797 }
798#endif
799
800 if (tunnel->err_count > 0) {
Wei Yongjunda6185d82009-02-24 23:34:48 -0800801 if (time_before(jiffies,
802 tunnel->err_time + IPTUNNEL_ERR_TIMEO)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 tunnel->err_count--;
804
805 dst_link_failure(skb);
806 } else
807 tunnel->err_count = 0;
808 }
809
Changli Gaod8d1f302010-06-10 23:31:35 -0700810 max_headroom = LL_RESERVED_SPACE(tdev) + gre_hlen + rt->dst.header_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811
Patrick McHardycfbba492007-07-09 15:33:40 -0700812 if (skb_headroom(skb) < max_headroom || skb_shared(skb)||
813 (skb_cloned(skb) && !skb_clone_writable(skb, 0))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom);
Timo Teräs243aad82010-03-20 02:27:58 +0000815 if (max_headroom > dev->needed_headroom)
816 dev->needed_headroom = max_headroom;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 if (!new_skb) {
818 ip_rt_put(rt);
Eric Dumazet0bfbedb2009-10-05 00:11:22 -0700819 txq->tx_dropped++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 dev_kfree_skb(skb);
Patrick McHardy6ed10652009-06-23 06:03:08 +0000821 return NETDEV_TX_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 }
823 if (skb->sk)
824 skb_set_owner_w(new_skb, skb->sk);
825 dev_kfree_skb(skb);
826 skb = new_skb;
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700827 old_iph = ip_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 }
829
Herbert Xu64194c32008-10-09 12:03:17 -0700830 skb_reset_transport_header(skb);
Arnaldo Carvalho de Meloe2d1bca2007-04-10 20:46:21 -0700831 skb_push(skb, gre_hlen);
832 skb_reset_network_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
Patrick McHardy48d5cad2006-02-15 15:10:22 -0800834 IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED |
835 IPSKB_REROUTED);
Eric Dumazetadf30902009-06-02 05:19:30 +0000836 skb_dst_drop(skb);
Changli Gaod8d1f302010-06-10 23:31:35 -0700837 skb_dst_set(skb, &rt->dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838
839 /*
840 * Push down and install the IPIP header.
841 */
842
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700843 iph = ip_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 iph->version = 4;
845 iph->ihl = sizeof(struct iphdr) >> 2;
846 iph->frag_off = df;
847 iph->protocol = IPPROTO_GRE;
848 iph->tos = ipgre_ecn_encapsulate(tos, old_iph, skb);
849 iph->daddr = rt->rt_dst;
850 iph->saddr = rt->rt_src;
851
852 if ((iph->ttl = tiph->ttl) == 0) {
853 if (skb->protocol == htons(ETH_P_IP))
854 iph->ttl = old_iph->ttl;
855#ifdef CONFIG_IPV6
856 else if (skb->protocol == htons(ETH_P_IPV6))
Jianjun Kong6ed25332008-11-03 00:25:16 -0800857 iph->ttl = ((struct ipv6hdr *)old_iph)->hop_limit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858#endif
859 else
Changli Gaod8d1f302010-06-10 23:31:35 -0700860 iph->ttl = dst_metric(&rt->dst, RTAX_HOPLIMIT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861 }
862
Herbert Xue1a80002008-10-09 12:00:17 -0700863 ((__be16 *)(iph + 1))[0] = tunnel->parms.o_flags;
864 ((__be16 *)(iph + 1))[1] = (dev->type == ARPHRD_ETHER) ?
865 htons(ETH_P_TEB) : skb->protocol;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866
867 if (tunnel->parms.o_flags&(GRE_KEY|GRE_CSUM|GRE_SEQ)) {
Al Virod5a0a1e2006-11-08 00:23:14 -0800868 __be32 *ptr = (__be32*)(((u8*)iph) + tunnel->hlen - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869
870 if (tunnel->parms.o_flags&GRE_SEQ) {
871 ++tunnel->o_seqno;
872 *ptr = htonl(tunnel->o_seqno);
873 ptr--;
874 }
875 if (tunnel->parms.o_flags&GRE_KEY) {
876 *ptr = tunnel->parms.o_key;
877 ptr--;
878 }
879 if (tunnel->parms.o_flags&GRE_CSUM) {
880 *ptr = 0;
Al Viro5f92a732006-11-14 21:36:54 -0800881 *(__sum16*)ptr = ip_compute_csum((void*)(iph+1), skb->len - sizeof(struct iphdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 }
883 }
884
885 nf_reset(skb);
886
887 IPTUNNEL_XMIT();
Patrick McHardy6ed10652009-06-23 06:03:08 +0000888 return NETDEV_TX_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889
890tx_error_icmp:
891 dst_link_failure(skb);
892
893tx_error:
894 stats->tx_errors++;
895 dev_kfree_skb(skb);
Patrick McHardy6ed10652009-06-23 06:03:08 +0000896 return NETDEV_TX_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897}
898
Herbert Xu42aa9162008-10-09 11:59:32 -0700899static int ipgre_tunnel_bind_dev(struct net_device *dev)
Michal Schmidtee34c1e2007-12-13 09:46:32 -0800900{
901 struct net_device *tdev = NULL;
902 struct ip_tunnel *tunnel;
903 struct iphdr *iph;
904 int hlen = LL_MAX_HEADER;
905 int mtu = ETH_DATA_LEN;
906 int addend = sizeof(struct iphdr) + 4;
907
908 tunnel = netdev_priv(dev);
909 iph = &tunnel->parms.iph;
910
Herbert Xuc95b8192008-10-09 11:58:54 -0700911 /* Guess output device to choose reasonable mtu and needed_headroom */
Michal Schmidtee34c1e2007-12-13 09:46:32 -0800912
913 if (iph->daddr) {
914 struct flowi fl = { .oif = tunnel->parms.link,
915 .nl_u = { .ip4_u =
916 { .daddr = iph->daddr,
917 .saddr = iph->saddr,
918 .tos = RT_TOS(iph->tos) } },
919 .proto = IPPROTO_GRE };
920 struct rtable *rt;
Pavel Emelyanov96635522008-04-16 01:10:44 -0700921 if (!ip_route_output_key(dev_net(dev), &rt, &fl)) {
Changli Gaod8d1f302010-06-10 23:31:35 -0700922 tdev = rt->dst.dev;
Michal Schmidtee34c1e2007-12-13 09:46:32 -0800923 ip_rt_put(rt);
924 }
Herbert Xue1a80002008-10-09 12:00:17 -0700925
926 if (dev->type != ARPHRD_ETHER)
927 dev->flags |= IFF_POINTOPOINT;
Michal Schmidtee34c1e2007-12-13 09:46:32 -0800928 }
929
930 if (!tdev && tunnel->parms.link)
Pavel Emelyanov96635522008-04-16 01:10:44 -0700931 tdev = __dev_get_by_index(dev_net(dev), tunnel->parms.link);
Michal Schmidtee34c1e2007-12-13 09:46:32 -0800932
933 if (tdev) {
Herbert Xuc95b8192008-10-09 11:58:54 -0700934 hlen = tdev->hard_header_len + tdev->needed_headroom;
Michal Schmidtee34c1e2007-12-13 09:46:32 -0800935 mtu = tdev->mtu;
936 }
937 dev->iflink = tunnel->parms.link;
938
939 /* Precalculate GRE options length */
940 if (tunnel->parms.o_flags&(GRE_CSUM|GRE_KEY|GRE_SEQ)) {
941 if (tunnel->parms.o_flags&GRE_CSUM)
942 addend += 4;
943 if (tunnel->parms.o_flags&GRE_KEY)
944 addend += 4;
945 if (tunnel->parms.o_flags&GRE_SEQ)
946 addend += 4;
947 }
Herbert Xuc95b8192008-10-09 11:58:54 -0700948 dev->needed_headroom = addend + hlen;
Tom Goff8cdb0452009-08-14 16:33:56 -0700949 mtu -= dev->hard_header_len + addend;
Herbert Xu42aa9162008-10-09 11:59:32 -0700950
951 if (mtu < 68)
952 mtu = 68;
953
Michal Schmidtee34c1e2007-12-13 09:46:32 -0800954 tunnel->hlen = addend;
955
Herbert Xu42aa9162008-10-09 11:59:32 -0700956 return mtu;
Michal Schmidtee34c1e2007-12-13 09:46:32 -0800957}
958
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959static int
960ipgre_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
961{
962 int err = 0;
963 struct ip_tunnel_parm p;
964 struct ip_tunnel *t;
Pavel Emelyanovf57e7d52008-04-16 01:09:22 -0700965 struct net *net = dev_net(dev);
966 struct ipgre_net *ign = net_generic(net, ipgre_net_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967
968 switch (cmd) {
969 case SIOCGETTUNNEL:
970 t = NULL;
Pavel Emelyanov7daa0002008-04-16 01:10:05 -0700971 if (dev == ign->fb_tunnel_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972 if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) {
973 err = -EFAULT;
974 break;
975 }
Pavel Emelyanovf57e7d52008-04-16 01:09:22 -0700976 t = ipgre_tunnel_locate(net, &p, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977 }
978 if (t == NULL)
Patrick McHardy2941a482006-01-08 22:05:26 -0800979 t = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980 memcpy(&p, &t->parms, sizeof(p));
981 if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p)))
982 err = -EFAULT;
983 break;
984
985 case SIOCADDTUNNEL:
986 case SIOCCHGTUNNEL:
987 err = -EPERM;
988 if (!capable(CAP_NET_ADMIN))
989 goto done;
990
991 err = -EFAULT;
992 if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
993 goto done;
994
995 err = -EINVAL;
996 if (p.iph.version != 4 || p.iph.protocol != IPPROTO_GRE ||
997 p.iph.ihl != 5 || (p.iph.frag_off&htons(~IP_DF)) ||
998 ((p.i_flags|p.o_flags)&(GRE_VERSION|GRE_ROUTING)))
999 goto done;
1000 if (p.iph.ttl)
1001 p.iph.frag_off |= htons(IP_DF);
1002
1003 if (!(p.i_flags&GRE_KEY))
1004 p.i_key = 0;
1005 if (!(p.o_flags&GRE_KEY))
1006 p.o_key = 0;
1007
Pavel Emelyanovf57e7d52008-04-16 01:09:22 -07001008 t = ipgre_tunnel_locate(net, &p, cmd == SIOCADDTUNNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009
Pavel Emelyanov7daa0002008-04-16 01:10:05 -07001010 if (dev != ign->fb_tunnel_dev && cmd == SIOCCHGTUNNEL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 if (t != NULL) {
1012 if (t->dev != dev) {
1013 err = -EEXIST;
1014 break;
1015 }
1016 } else {
Eric Dumazet15078502010-09-15 11:07:53 +00001017 unsigned int nflags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018
Patrick McHardy2941a482006-01-08 22:05:26 -08001019 t = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020
Joe Perchesf97c1e02007-12-16 13:45:43 -08001021 if (ipv4_is_multicast(p.iph.daddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 nflags = IFF_BROADCAST;
1023 else if (p.iph.daddr)
1024 nflags = IFF_POINTOPOINT;
1025
1026 if ((dev->flags^nflags)&(IFF_POINTOPOINT|IFF_BROADCAST)) {
1027 err = -EINVAL;
1028 break;
1029 }
Pavel Emelyanovf57e7d52008-04-16 01:09:22 -07001030 ipgre_tunnel_unlink(ign, t);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031 t->parms.iph.saddr = p.iph.saddr;
1032 t->parms.iph.daddr = p.iph.daddr;
1033 t->parms.i_key = p.i_key;
1034 t->parms.o_key = p.o_key;
1035 memcpy(dev->dev_addr, &p.iph.saddr, 4);
1036 memcpy(dev->broadcast, &p.iph.daddr, 4);
Pavel Emelyanovf57e7d52008-04-16 01:09:22 -07001037 ipgre_tunnel_link(ign, t);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 netdev_state_change(dev);
1039 }
1040 }
1041
1042 if (t) {
1043 err = 0;
1044 if (cmd == SIOCCHGTUNNEL) {
1045 t->parms.iph.ttl = p.iph.ttl;
1046 t->parms.iph.tos = p.iph.tos;
1047 t->parms.iph.frag_off = p.iph.frag_off;
Michal Schmidtee34c1e2007-12-13 09:46:32 -08001048 if (t->parms.link != p.link) {
1049 t->parms.link = p.link;
Herbert Xu42aa9162008-10-09 11:59:32 -07001050 dev->mtu = ipgre_tunnel_bind_dev(dev);
Michal Schmidtee34c1e2007-12-13 09:46:32 -08001051 netdev_state_change(dev);
1052 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053 }
1054 if (copy_to_user(ifr->ifr_ifru.ifru_data, &t->parms, sizeof(p)))
1055 err = -EFAULT;
1056 } else
1057 err = (cmd == SIOCADDTUNNEL ? -ENOBUFS : -ENOENT);
1058 break;
1059
1060 case SIOCDELTUNNEL:
1061 err = -EPERM;
1062 if (!capable(CAP_NET_ADMIN))
1063 goto done;
1064
Pavel Emelyanov7daa0002008-04-16 01:10:05 -07001065 if (dev == ign->fb_tunnel_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066 err = -EFAULT;
1067 if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
1068 goto done;
1069 err = -ENOENT;
Pavel Emelyanovf57e7d52008-04-16 01:09:22 -07001070 if ((t = ipgre_tunnel_locate(net, &p, 0)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071 goto done;
1072 err = -EPERM;
Pavel Emelyanov7daa0002008-04-16 01:10:05 -07001073 if (t == netdev_priv(ign->fb_tunnel_dev))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074 goto done;
1075 dev = t->dev;
1076 }
Stephen Hemminger22f8cde2007-02-07 00:09:58 -08001077 unregister_netdevice(dev);
1078 err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 break;
1080
1081 default:
1082 err = -EINVAL;
1083 }
1084
1085done:
1086 return err;
1087}
1088
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089static int ipgre_tunnel_change_mtu(struct net_device *dev, int new_mtu)
1090{
Patrick McHardy2941a482006-01-08 22:05:26 -08001091 struct ip_tunnel *tunnel = netdev_priv(dev);
Herbert Xuc95b8192008-10-09 11:58:54 -07001092 if (new_mtu < 68 ||
1093 new_mtu > 0xFFF8 - dev->hard_header_len - tunnel->hlen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094 return -EINVAL;
1095 dev->mtu = new_mtu;
1096 return 0;
1097}
1098
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099/* Nice toy. Unfortunately, useless in real life :-)
1100 It allows to construct virtual multiprotocol broadcast "LAN"
1101 over the Internet, provided multicast routing is tuned.
1102
1103
1104 I have no idea was this bicycle invented before me,
1105 so that I had to set ARPHRD_IPGRE to a random value.
1106 I have an impression, that Cisco could make something similar,
1107 but this feature is apparently missing in IOS<=11.2(8).
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001108
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109 I set up 10.66.66/24 and fec0:6666:6666::0/96 as virtual networks
1110 with broadcast 224.66.66.66. If you have access to mbone, play with me :-)
1111
1112 ping -t 255 224.66.66.66
1113
1114 If nobody answers, mbone does not work.
1115
1116 ip tunnel add Universe mode gre remote 224.66.66.66 local <Your_real_addr> ttl 255
1117 ip addr add 10.66.66.<somewhat>/24 dev Universe
1118 ifconfig Universe up
1119 ifconfig Universe add fe80::<Your_real_addr>/10
1120 ifconfig Universe add fec0:6666:6666::<Your_real_addr>/96
1121 ftp 10.66.66.66
1122 ...
1123 ftp fec0:6666:6666::193.233.7.65
1124 ...
1125
1126 */
1127
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -07001128static int ipgre_header(struct sk_buff *skb, struct net_device *dev,
1129 unsigned short type,
Eric Dumazet15078502010-09-15 11:07:53 +00001130 const void *daddr, const void *saddr, unsigned int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131{
Patrick McHardy2941a482006-01-08 22:05:26 -08001132 struct ip_tunnel *t = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 struct iphdr *iph = (struct iphdr *)skb_push(skb, t->hlen);
Al Virod5a0a1e2006-11-08 00:23:14 -08001134 __be16 *p = (__be16*)(iph+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135
1136 memcpy(iph, &t->parms.iph, sizeof(struct iphdr));
1137 p[0] = t->parms.o_flags;
1138 p[1] = htons(type);
1139
1140 /*
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001141 * Set the source hardware address.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142 */
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001143
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144 if (saddr)
1145 memcpy(&iph->saddr, saddr, 4);
Timo Teräs6d55cb92010-03-03 04:01:13 +00001146 if (daddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147 memcpy(&iph->daddr, daddr, 4);
Timo Teräs6d55cb92010-03-03 04:01:13 +00001148 if (iph->daddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149 return t->hlen;
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001150
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151 return -t->hlen;
1152}
1153
Timo Teras6a5f44d2007-10-23 20:31:53 -07001154static int ipgre_header_parse(const struct sk_buff *skb, unsigned char *haddr)
1155{
Jianjun Kong6ed25332008-11-03 00:25:16 -08001156 struct iphdr *iph = (struct iphdr *) skb_mac_header(skb);
Timo Teras6a5f44d2007-10-23 20:31:53 -07001157 memcpy(haddr, &iph->saddr, 4);
1158 return 4;
1159}
1160
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -07001161static const struct header_ops ipgre_header_ops = {
1162 .create = ipgre_header,
Timo Teras6a5f44d2007-10-23 20:31:53 -07001163 .parse = ipgre_header_parse,
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -07001164};
1165
Timo Teras6a5f44d2007-10-23 20:31:53 -07001166#ifdef CONFIG_NET_IPGRE_BROADCAST
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167static int ipgre_open(struct net_device *dev)
1168{
Patrick McHardy2941a482006-01-08 22:05:26 -08001169 struct ip_tunnel *t = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170
Joe Perchesf97c1e02007-12-16 13:45:43 -08001171 if (ipv4_is_multicast(t->parms.iph.daddr)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172 struct flowi fl = { .oif = t->parms.link,
1173 .nl_u = { .ip4_u =
1174 { .daddr = t->parms.iph.daddr,
1175 .saddr = t->parms.iph.saddr,
1176 .tos = RT_TOS(t->parms.iph.tos) } },
1177 .proto = IPPROTO_GRE };
1178 struct rtable *rt;
Pavel Emelyanov96635522008-04-16 01:10:44 -07001179 if (ip_route_output_key(dev_net(dev), &rt, &fl))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180 return -EADDRNOTAVAIL;
Changli Gaod8d1f302010-06-10 23:31:35 -07001181 dev = rt->dst.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182 ip_rt_put(rt);
Herbert Xue5ed6392005-10-03 14:35:55 -07001183 if (__in_dev_get_rtnl(dev) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 return -EADDRNOTAVAIL;
1185 t->mlink = dev->ifindex;
Herbert Xue5ed6392005-10-03 14:35:55 -07001186 ip_mc_inc_group(__in_dev_get_rtnl(dev), t->parms.iph.daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187 }
1188 return 0;
1189}
1190
1191static int ipgre_close(struct net_device *dev)
1192{
Patrick McHardy2941a482006-01-08 22:05:26 -08001193 struct ip_tunnel *t = netdev_priv(dev);
Stephen Hemmingerb8c26a32008-11-20 20:34:29 -08001194
Joe Perchesf97c1e02007-12-16 13:45:43 -08001195 if (ipv4_is_multicast(t->parms.iph.daddr) && t->mlink) {
Denis V. Lunev7fee0ca2008-01-21 17:32:38 -08001196 struct in_device *in_dev;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001197 in_dev = inetdev_by_index(dev_net(dev), t->mlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198 if (in_dev) {
1199 ip_mc_dec_group(in_dev, t->parms.iph.daddr);
1200 in_dev_put(in_dev);
1201 }
1202 }
1203 return 0;
1204}
1205
1206#endif
1207
Stephen Hemmingerb8c26a32008-11-20 20:34:29 -08001208static const struct net_device_ops ipgre_netdev_ops = {
1209 .ndo_init = ipgre_tunnel_init,
1210 .ndo_uninit = ipgre_tunnel_uninit,
1211#ifdef CONFIG_NET_IPGRE_BROADCAST
1212 .ndo_open = ipgre_open,
1213 .ndo_stop = ipgre_close,
1214#endif
1215 .ndo_start_xmit = ipgre_tunnel_xmit,
1216 .ndo_do_ioctl = ipgre_tunnel_ioctl,
1217 .ndo_change_mtu = ipgre_tunnel_change_mtu,
1218};
1219
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220static void ipgre_tunnel_setup(struct net_device *dev)
1221{
Stephen Hemmingerb8c26a32008-11-20 20:34:29 -08001222 dev->netdev_ops = &ipgre_netdev_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223 dev->destructor = free_netdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224
1225 dev->type = ARPHRD_IPGRE;
Herbert Xuc95b8192008-10-09 11:58:54 -07001226 dev->needed_headroom = LL_MAX_HEADER + sizeof(struct iphdr) + 4;
Kris Katterjohn46f25df2006-01-05 16:35:42 -08001227 dev->mtu = ETH_DATA_LEN - sizeof(struct iphdr) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228 dev->flags = IFF_NOARP;
1229 dev->iflink = 0;
1230 dev->addr_len = 4;
Pavel Emelyanov0b67ece2008-04-16 01:11:13 -07001231 dev->features |= NETIF_F_NETNS_LOCAL;
Eric Dumazet108bfa82009-05-28 22:35:10 +00001232 dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233}
1234
1235static int ipgre_tunnel_init(struct net_device *dev)
1236{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237 struct ip_tunnel *tunnel;
1238 struct iphdr *iph;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239
Patrick McHardy2941a482006-01-08 22:05:26 -08001240 tunnel = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241 iph = &tunnel->parms.iph;
1242
1243 tunnel->dev = dev;
1244 strcpy(tunnel->parms.name, dev->name);
1245
1246 memcpy(dev->dev_addr, &tunnel->parms.iph.saddr, 4);
1247 memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4);
1248
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249 if (iph->daddr) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250#ifdef CONFIG_NET_IPGRE_BROADCAST
Joe Perchesf97c1e02007-12-16 13:45:43 -08001251 if (ipv4_is_multicast(iph->daddr)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252 if (!iph->saddr)
1253 return -EINVAL;
1254 dev->flags = IFF_BROADCAST;
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -07001255 dev->header_ops = &ipgre_header_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 }
1257#endif
Michal Schmidtee34c1e2007-12-13 09:46:32 -08001258 } else
Timo Teras6a5f44d2007-10-23 20:31:53 -07001259 dev->header_ops = &ipgre_header_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261 return 0;
1262}
1263
Stephen Hemmingerb8c26a32008-11-20 20:34:29 -08001264static void ipgre_fb_tunnel_init(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265{
Patrick McHardy2941a482006-01-08 22:05:26 -08001266 struct ip_tunnel *tunnel = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001267 struct iphdr *iph = &tunnel->parms.iph;
Pavel Emelyanoveb8ce742008-04-16 01:10:26 -07001268 struct ipgre_net *ign = net_generic(dev_net(dev), ipgre_net_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269
1270 tunnel->dev = dev;
1271 strcpy(tunnel->parms.name, dev->name);
1272
1273 iph->version = 4;
1274 iph->protocol = IPPROTO_GRE;
1275 iph->ihl = 5;
1276 tunnel->hlen = sizeof(struct iphdr) + 4;
1277
1278 dev_hold(dev);
Eric Dumazet15078502010-09-15 11:07:53 +00001279 rcu_assign_pointer(ign->tunnels_wc[0], tunnel);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280}
1281
1282
Dmitry Kozlov00959ad2010-08-21 23:05:39 -07001283static const struct gre_protocol ipgre_protocol = {
1284 .handler = ipgre_rcv,
1285 .err_handler = ipgre_err,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286};
1287
Eric Dumazeteef6dd62009-10-27 07:07:16 +00001288static void ipgre_destroy_tunnels(struct ipgre_net *ign, struct list_head *head)
Pavel Emelyanoveb8ce742008-04-16 01:10:26 -07001289{
1290 int prio;
1291
1292 for (prio = 0; prio < 4; prio++) {
1293 int h;
1294 for (h = 0; h < HASH_SIZE; h++) {
Eric Dumazet15078502010-09-15 11:07:53 +00001295 struct ip_tunnel *t;
1296
1297 t = rtnl_dereference(ign->tunnels[prio][h]);
Eric Dumazeteef6dd62009-10-27 07:07:16 +00001298
1299 while (t != NULL) {
1300 unregister_netdevice_queue(t->dev, head);
Eric Dumazet15078502010-09-15 11:07:53 +00001301 t = rtnl_dereference(t->next);
Eric Dumazeteef6dd62009-10-27 07:07:16 +00001302 }
Pavel Emelyanoveb8ce742008-04-16 01:10:26 -07001303 }
1304 }
1305}
1306
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00001307static int __net_init ipgre_init_net(struct net *net)
Pavel Emelyanov59a4c752008-04-16 01:08:53 -07001308{
Eric W. Biedermancfb8fbf2009-11-29 15:46:13 +00001309 struct ipgre_net *ign = net_generic(net, ipgre_net_id);
Pavel Emelyanov59a4c752008-04-16 01:08:53 -07001310 int err;
Pavel Emelyanov59a4c752008-04-16 01:08:53 -07001311
Pavel Emelyanov7daa0002008-04-16 01:10:05 -07001312 ign->fb_tunnel_dev = alloc_netdev(sizeof(struct ip_tunnel), "gre0",
1313 ipgre_tunnel_setup);
1314 if (!ign->fb_tunnel_dev) {
1315 err = -ENOMEM;
1316 goto err_alloc_dev;
1317 }
Alexey Dobriyanbe77e592008-11-23 17:26:26 -08001318 dev_net_set(ign->fb_tunnel_dev, net);
Pavel Emelyanov7daa0002008-04-16 01:10:05 -07001319
Stephen Hemmingerb8c26a32008-11-20 20:34:29 -08001320 ipgre_fb_tunnel_init(ign->fb_tunnel_dev);
Herbert Xuc19e6542008-10-09 11:59:55 -07001321 ign->fb_tunnel_dev->rtnl_link_ops = &ipgre_link_ops;
Pavel Emelyanov7daa0002008-04-16 01:10:05 -07001322
1323 if ((err = register_netdev(ign->fb_tunnel_dev)))
1324 goto err_reg_dev;
1325
Pavel Emelyanov59a4c752008-04-16 01:08:53 -07001326 return 0;
1327
Pavel Emelyanov7daa0002008-04-16 01:10:05 -07001328err_reg_dev:
1329 free_netdev(ign->fb_tunnel_dev);
1330err_alloc_dev:
Pavel Emelyanov59a4c752008-04-16 01:08:53 -07001331 return err;
1332}
1333
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00001334static void __net_exit ipgre_exit_net(struct net *net)
Pavel Emelyanov59a4c752008-04-16 01:08:53 -07001335{
1336 struct ipgre_net *ign;
Eric Dumazeteef6dd62009-10-27 07:07:16 +00001337 LIST_HEAD(list);
Pavel Emelyanov59a4c752008-04-16 01:08:53 -07001338
1339 ign = net_generic(net, ipgre_net_id);
Pavel Emelyanov7daa0002008-04-16 01:10:05 -07001340 rtnl_lock();
Eric Dumazeteef6dd62009-10-27 07:07:16 +00001341 ipgre_destroy_tunnels(ign, &list);
1342 unregister_netdevice_many(&list);
Pavel Emelyanov7daa0002008-04-16 01:10:05 -07001343 rtnl_unlock();
Pavel Emelyanov59a4c752008-04-16 01:08:53 -07001344}
1345
1346static struct pernet_operations ipgre_net_ops = {
1347 .init = ipgre_init_net,
1348 .exit = ipgre_exit_net,
Eric W. Biedermancfb8fbf2009-11-29 15:46:13 +00001349 .id = &ipgre_net_id,
1350 .size = sizeof(struct ipgre_net),
Pavel Emelyanov59a4c752008-04-16 01:08:53 -07001351};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352
Herbert Xuc19e6542008-10-09 11:59:55 -07001353static int ipgre_tunnel_validate(struct nlattr *tb[], struct nlattr *data[])
1354{
1355 __be16 flags;
1356
1357 if (!data)
1358 return 0;
1359
1360 flags = 0;
1361 if (data[IFLA_GRE_IFLAGS])
1362 flags |= nla_get_be16(data[IFLA_GRE_IFLAGS]);
1363 if (data[IFLA_GRE_OFLAGS])
1364 flags |= nla_get_be16(data[IFLA_GRE_OFLAGS]);
1365 if (flags & (GRE_VERSION|GRE_ROUTING))
1366 return -EINVAL;
1367
1368 return 0;
1369}
1370
Herbert Xue1a80002008-10-09 12:00:17 -07001371static int ipgre_tap_validate(struct nlattr *tb[], struct nlattr *data[])
1372{
1373 __be32 daddr;
1374
1375 if (tb[IFLA_ADDRESS]) {
1376 if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN)
1377 return -EINVAL;
1378 if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS])))
1379 return -EADDRNOTAVAIL;
1380 }
1381
1382 if (!data)
1383 goto out;
1384
1385 if (data[IFLA_GRE_REMOTE]) {
1386 memcpy(&daddr, nla_data(data[IFLA_GRE_REMOTE]), 4);
1387 if (!daddr)
1388 return -EINVAL;
1389 }
1390
1391out:
1392 return ipgre_tunnel_validate(tb, data);
1393}
1394
Herbert Xuc19e6542008-10-09 11:59:55 -07001395static void ipgre_netlink_parms(struct nlattr *data[],
1396 struct ip_tunnel_parm *parms)
1397{
Herbert Xu7bb82d92008-10-11 12:20:15 -07001398 memset(parms, 0, sizeof(*parms));
Herbert Xuc19e6542008-10-09 11:59:55 -07001399
1400 parms->iph.protocol = IPPROTO_GRE;
1401
1402 if (!data)
1403 return;
1404
1405 if (data[IFLA_GRE_LINK])
1406 parms->link = nla_get_u32(data[IFLA_GRE_LINK]);
1407
1408 if (data[IFLA_GRE_IFLAGS])
1409 parms->i_flags = nla_get_be16(data[IFLA_GRE_IFLAGS]);
1410
1411 if (data[IFLA_GRE_OFLAGS])
1412 parms->o_flags = nla_get_be16(data[IFLA_GRE_OFLAGS]);
1413
1414 if (data[IFLA_GRE_IKEY])
1415 parms->i_key = nla_get_be32(data[IFLA_GRE_IKEY]);
1416
1417 if (data[IFLA_GRE_OKEY])
1418 parms->o_key = nla_get_be32(data[IFLA_GRE_OKEY]);
1419
1420 if (data[IFLA_GRE_LOCAL])
Patrick McHardy4d74f8b2008-10-10 12:11:06 -07001421 parms->iph.saddr = nla_get_be32(data[IFLA_GRE_LOCAL]);
Herbert Xuc19e6542008-10-09 11:59:55 -07001422
1423 if (data[IFLA_GRE_REMOTE])
Patrick McHardy4d74f8b2008-10-10 12:11:06 -07001424 parms->iph.daddr = nla_get_be32(data[IFLA_GRE_REMOTE]);
Herbert Xuc19e6542008-10-09 11:59:55 -07001425
1426 if (data[IFLA_GRE_TTL])
1427 parms->iph.ttl = nla_get_u8(data[IFLA_GRE_TTL]);
1428
1429 if (data[IFLA_GRE_TOS])
1430 parms->iph.tos = nla_get_u8(data[IFLA_GRE_TOS]);
1431
1432 if (!data[IFLA_GRE_PMTUDISC] || nla_get_u8(data[IFLA_GRE_PMTUDISC]))
1433 parms->iph.frag_off = htons(IP_DF);
1434}
1435
Herbert Xue1a80002008-10-09 12:00:17 -07001436static int ipgre_tap_init(struct net_device *dev)
1437{
1438 struct ip_tunnel *tunnel;
1439
1440 tunnel = netdev_priv(dev);
1441
1442 tunnel->dev = dev;
1443 strcpy(tunnel->parms.name, dev->name);
1444
1445 ipgre_tunnel_bind_dev(dev);
1446
1447 return 0;
1448}
1449
Stephen Hemmingerb8c26a32008-11-20 20:34:29 -08001450static const struct net_device_ops ipgre_tap_netdev_ops = {
1451 .ndo_init = ipgre_tap_init,
1452 .ndo_uninit = ipgre_tunnel_uninit,
1453 .ndo_start_xmit = ipgre_tunnel_xmit,
1454 .ndo_set_mac_address = eth_mac_addr,
1455 .ndo_validate_addr = eth_validate_addr,
1456 .ndo_change_mtu = ipgre_tunnel_change_mtu,
1457};
1458
Herbert Xue1a80002008-10-09 12:00:17 -07001459static void ipgre_tap_setup(struct net_device *dev)
1460{
1461
1462 ether_setup(dev);
1463
Herbert Xu2e9526b2009-10-30 05:51:48 +00001464 dev->netdev_ops = &ipgre_tap_netdev_ops;
Herbert Xue1a80002008-10-09 12:00:17 -07001465 dev->destructor = free_netdev;
Herbert Xue1a80002008-10-09 12:00:17 -07001466
1467 dev->iflink = 0;
1468 dev->features |= NETIF_F_NETNS_LOCAL;
1469}
1470
Eric W. Biederman81adee42009-11-08 00:53:51 -08001471static int ipgre_newlink(struct net *src_net, struct net_device *dev, struct nlattr *tb[],
Herbert Xuc19e6542008-10-09 11:59:55 -07001472 struct nlattr *data[])
1473{
1474 struct ip_tunnel *nt;
1475 struct net *net = dev_net(dev);
1476 struct ipgre_net *ign = net_generic(net, ipgre_net_id);
1477 int mtu;
1478 int err;
1479
1480 nt = netdev_priv(dev);
1481 ipgre_netlink_parms(data, &nt->parms);
1482
Herbert Xue1a80002008-10-09 12:00:17 -07001483 if (ipgre_tunnel_find(net, &nt->parms, dev->type))
Herbert Xuc19e6542008-10-09 11:59:55 -07001484 return -EEXIST;
1485
Herbert Xue1a80002008-10-09 12:00:17 -07001486 if (dev->type == ARPHRD_ETHER && !tb[IFLA_ADDRESS])
1487 random_ether_addr(dev->dev_addr);
1488
Herbert Xuc19e6542008-10-09 11:59:55 -07001489 mtu = ipgre_tunnel_bind_dev(dev);
1490 if (!tb[IFLA_MTU])
1491 dev->mtu = mtu;
1492
1493 err = register_netdevice(dev);
1494 if (err)
1495 goto out;
1496
1497 dev_hold(dev);
1498 ipgre_tunnel_link(ign, nt);
1499
1500out:
1501 return err;
1502}
1503
1504static int ipgre_changelink(struct net_device *dev, struct nlattr *tb[],
1505 struct nlattr *data[])
1506{
1507 struct ip_tunnel *t, *nt;
1508 struct net *net = dev_net(dev);
1509 struct ipgre_net *ign = net_generic(net, ipgre_net_id);
1510 struct ip_tunnel_parm p;
1511 int mtu;
1512
1513 if (dev == ign->fb_tunnel_dev)
1514 return -EINVAL;
1515
1516 nt = netdev_priv(dev);
1517 ipgre_netlink_parms(data, &p);
1518
1519 t = ipgre_tunnel_locate(net, &p, 0);
1520
1521 if (t) {
1522 if (t->dev != dev)
1523 return -EEXIST;
1524 } else {
Herbert Xuc19e6542008-10-09 11:59:55 -07001525 t = nt;
1526
Herbert Xu2e9526b2009-10-30 05:51:48 +00001527 if (dev->type != ARPHRD_ETHER) {
Eric Dumazet15078502010-09-15 11:07:53 +00001528 unsigned int nflags = 0;
Herbert Xuc19e6542008-10-09 11:59:55 -07001529
Herbert Xu2e9526b2009-10-30 05:51:48 +00001530 if (ipv4_is_multicast(p.iph.daddr))
1531 nflags = IFF_BROADCAST;
1532 else if (p.iph.daddr)
1533 nflags = IFF_POINTOPOINT;
1534
1535 if ((dev->flags ^ nflags) &
1536 (IFF_POINTOPOINT | IFF_BROADCAST))
1537 return -EINVAL;
1538 }
Herbert Xuc19e6542008-10-09 11:59:55 -07001539
1540 ipgre_tunnel_unlink(ign, t);
1541 t->parms.iph.saddr = p.iph.saddr;
1542 t->parms.iph.daddr = p.iph.daddr;
1543 t->parms.i_key = p.i_key;
Herbert Xu2e9526b2009-10-30 05:51:48 +00001544 if (dev->type != ARPHRD_ETHER) {
1545 memcpy(dev->dev_addr, &p.iph.saddr, 4);
1546 memcpy(dev->broadcast, &p.iph.daddr, 4);
1547 }
Herbert Xuc19e6542008-10-09 11:59:55 -07001548 ipgre_tunnel_link(ign, t);
1549 netdev_state_change(dev);
1550 }
1551
1552 t->parms.o_key = p.o_key;
1553 t->parms.iph.ttl = p.iph.ttl;
1554 t->parms.iph.tos = p.iph.tos;
1555 t->parms.iph.frag_off = p.iph.frag_off;
1556
1557 if (t->parms.link != p.link) {
1558 t->parms.link = p.link;
1559 mtu = ipgre_tunnel_bind_dev(dev);
1560 if (!tb[IFLA_MTU])
1561 dev->mtu = mtu;
1562 netdev_state_change(dev);
1563 }
1564
1565 return 0;
1566}
1567
1568static size_t ipgre_get_size(const struct net_device *dev)
1569{
1570 return
1571 /* IFLA_GRE_LINK */
1572 nla_total_size(4) +
1573 /* IFLA_GRE_IFLAGS */
1574 nla_total_size(2) +
1575 /* IFLA_GRE_OFLAGS */
1576 nla_total_size(2) +
1577 /* IFLA_GRE_IKEY */
1578 nla_total_size(4) +
1579 /* IFLA_GRE_OKEY */
1580 nla_total_size(4) +
1581 /* IFLA_GRE_LOCAL */
1582 nla_total_size(4) +
1583 /* IFLA_GRE_REMOTE */
1584 nla_total_size(4) +
1585 /* IFLA_GRE_TTL */
1586 nla_total_size(1) +
1587 /* IFLA_GRE_TOS */
1588 nla_total_size(1) +
1589 /* IFLA_GRE_PMTUDISC */
1590 nla_total_size(1) +
1591 0;
1592}
1593
1594static int ipgre_fill_info(struct sk_buff *skb, const struct net_device *dev)
1595{
1596 struct ip_tunnel *t = netdev_priv(dev);
1597 struct ip_tunnel_parm *p = &t->parms;
1598
1599 NLA_PUT_U32(skb, IFLA_GRE_LINK, p->link);
1600 NLA_PUT_BE16(skb, IFLA_GRE_IFLAGS, p->i_flags);
1601 NLA_PUT_BE16(skb, IFLA_GRE_OFLAGS, p->o_flags);
Patrick McHardyba9e64b2008-10-10 12:10:30 -07001602 NLA_PUT_BE32(skb, IFLA_GRE_IKEY, p->i_key);
1603 NLA_PUT_BE32(skb, IFLA_GRE_OKEY, p->o_key);
Patrick McHardy4d74f8b2008-10-10 12:11:06 -07001604 NLA_PUT_BE32(skb, IFLA_GRE_LOCAL, p->iph.saddr);
1605 NLA_PUT_BE32(skb, IFLA_GRE_REMOTE, p->iph.daddr);
Herbert Xuc19e6542008-10-09 11:59:55 -07001606 NLA_PUT_U8(skb, IFLA_GRE_TTL, p->iph.ttl);
1607 NLA_PUT_U8(skb, IFLA_GRE_TOS, p->iph.tos);
1608 NLA_PUT_U8(skb, IFLA_GRE_PMTUDISC, !!(p->iph.frag_off & htons(IP_DF)));
1609
1610 return 0;
1611
1612nla_put_failure:
1613 return -EMSGSIZE;
1614}
1615
1616static const struct nla_policy ipgre_policy[IFLA_GRE_MAX + 1] = {
1617 [IFLA_GRE_LINK] = { .type = NLA_U32 },
1618 [IFLA_GRE_IFLAGS] = { .type = NLA_U16 },
1619 [IFLA_GRE_OFLAGS] = { .type = NLA_U16 },
1620 [IFLA_GRE_IKEY] = { .type = NLA_U32 },
1621 [IFLA_GRE_OKEY] = { .type = NLA_U32 },
Patrick McHardy4d74f8b2008-10-10 12:11:06 -07001622 [IFLA_GRE_LOCAL] = { .len = FIELD_SIZEOF(struct iphdr, saddr) },
1623 [IFLA_GRE_REMOTE] = { .len = FIELD_SIZEOF(struct iphdr, daddr) },
Herbert Xuc19e6542008-10-09 11:59:55 -07001624 [IFLA_GRE_TTL] = { .type = NLA_U8 },
1625 [IFLA_GRE_TOS] = { .type = NLA_U8 },
1626 [IFLA_GRE_PMTUDISC] = { .type = NLA_U8 },
1627};
1628
1629static struct rtnl_link_ops ipgre_link_ops __read_mostly = {
1630 .kind = "gre",
1631 .maxtype = IFLA_GRE_MAX,
1632 .policy = ipgre_policy,
1633 .priv_size = sizeof(struct ip_tunnel),
1634 .setup = ipgre_tunnel_setup,
1635 .validate = ipgre_tunnel_validate,
1636 .newlink = ipgre_newlink,
1637 .changelink = ipgre_changelink,
1638 .get_size = ipgre_get_size,
1639 .fill_info = ipgre_fill_info,
1640};
1641
Herbert Xue1a80002008-10-09 12:00:17 -07001642static struct rtnl_link_ops ipgre_tap_ops __read_mostly = {
1643 .kind = "gretap",
1644 .maxtype = IFLA_GRE_MAX,
1645 .policy = ipgre_policy,
1646 .priv_size = sizeof(struct ip_tunnel),
1647 .setup = ipgre_tap_setup,
1648 .validate = ipgre_tap_validate,
1649 .newlink = ipgre_newlink,
1650 .changelink = ipgre_changelink,
1651 .get_size = ipgre_get_size,
1652 .fill_info = ipgre_fill_info,
1653};
1654
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655/*
1656 * And now the modules code and kernel interface.
1657 */
1658
1659static int __init ipgre_init(void)
1660{
1661 int err;
1662
1663 printk(KERN_INFO "GRE over IPv4 tunneling driver\n");
1664
Eric W. Biedermancfb8fbf2009-11-29 15:46:13 +00001665 err = register_pernet_device(&ipgre_net_ops);
Pavel Emelyanov59a4c752008-04-16 01:08:53 -07001666 if (err < 0)
Alexey Dobriyanc2892f02010-02-16 07:57:44 +00001667 return err;
1668
Dmitry Kozlov00959ad2010-08-21 23:05:39 -07001669 err = gre_add_protocol(&ipgre_protocol, GREPROTO_CISCO);
Alexey Dobriyanc2892f02010-02-16 07:57:44 +00001670 if (err < 0) {
1671 printk(KERN_INFO "ipgre init: can't add protocol\n");
1672 goto add_proto_failed;
1673 }
Pavel Emelyanov7daa0002008-04-16 01:10:05 -07001674
Herbert Xuc19e6542008-10-09 11:59:55 -07001675 err = rtnl_link_register(&ipgre_link_ops);
1676 if (err < 0)
1677 goto rtnl_link_failed;
1678
Herbert Xue1a80002008-10-09 12:00:17 -07001679 err = rtnl_link_register(&ipgre_tap_ops);
1680 if (err < 0)
1681 goto tap_ops_failed;
1682
Herbert Xuc19e6542008-10-09 11:59:55 -07001683out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684 return err;
Herbert Xuc19e6542008-10-09 11:59:55 -07001685
Herbert Xue1a80002008-10-09 12:00:17 -07001686tap_ops_failed:
1687 rtnl_link_unregister(&ipgre_link_ops);
Herbert Xuc19e6542008-10-09 11:59:55 -07001688rtnl_link_failed:
Dmitry Kozlov00959ad2010-08-21 23:05:39 -07001689 gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO);
Alexey Dobriyanc2892f02010-02-16 07:57:44 +00001690add_proto_failed:
1691 unregister_pernet_device(&ipgre_net_ops);
Herbert Xuc19e6542008-10-09 11:59:55 -07001692 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693}
1694
Alexey Kuznetsovdb445752005-07-30 17:46:44 -07001695static void __exit ipgre_fini(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696{
Herbert Xue1a80002008-10-09 12:00:17 -07001697 rtnl_link_unregister(&ipgre_tap_ops);
Herbert Xuc19e6542008-10-09 11:59:55 -07001698 rtnl_link_unregister(&ipgre_link_ops);
Dmitry Kozlov00959ad2010-08-21 23:05:39 -07001699 if (gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO) < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700 printk(KERN_INFO "ipgre close: can't remove protocol\n");
Alexey Dobriyanc2892f02010-02-16 07:57:44 +00001701 unregister_pernet_device(&ipgre_net_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702}
1703
1704module_init(ipgre_init);
1705module_exit(ipgre_fini);
1706MODULE_LICENSE("GPL");
Patrick McHardy4d74f8b2008-10-10 12:11:06 -07001707MODULE_ALIAS_RTNL_LINK("gre");
1708MODULE_ALIAS_RTNL_LINK("gretap");