blob: 749e54889e821aa47bef63f494cea81b4cd29295 [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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070047
48#ifdef CONFIG_IPV6
49#include <net/ipv6.h>
50#include <net/ip6_fib.h>
51#include <net/ip6_route.h>
52#endif
53
54/*
55 Problems & solutions
56 --------------------
57
58 1. The most important issue is detecting local dead loops.
59 They would cause complete host lockup in transmit, which
60 would be "resolved" by stack overflow or, if queueing is enabled,
61 with infinite looping in net_bh.
62
63 We cannot track such dead loops during route installation,
64 it is infeasible task. The most general solutions would be
65 to keep skb->encapsulation counter (sort of local ttl),
66 and silently drop packet when it expires. It is the best
67 solution, but it supposes maintaing new variable in ALL
68 skb, even if no tunneling is used.
69
Eric Dumazeta43912a2009-09-23 10:28:33 +000070 Current solution: HARD_TX_LOCK lock breaks dead loops.
Linus Torvalds1da177e2005-04-16 15:20:36 -070071
72
73
74 2. Networking dead loops would not kill routers, but would really
75 kill network. IP hop limit plays role of "t->recursion" in this case,
76 if we copy it from packet being encapsulated to upper header.
77 It is very good solution, but it introduces two problems:
78
79 - Routing protocols, using packets with ttl=1 (OSPF, RIP2),
80 do not work over tunnels.
81 - traceroute does not work. I planned to relay ICMP from tunnel,
82 so that this problem would be solved and traceroute output
83 would even more informative. This idea appeared to be wrong:
84 only Linux complies to rfc1812 now (yes, guys, Linux is the only
85 true router now :-)), all routers (at least, in neighbourhood of mine)
86 return only 8 bytes of payload. It is the end.
87
88 Hence, if we want that OSPF worked or traceroute said something reasonable,
89 we should search for another solution.
90
91 One of them is to parse packet trying to detect inner encapsulation
92 made by our node. It is difficult or even impossible, especially,
93 taking into account fragmentation. TO be short, tt is not solution at all.
94
95 Current solution: The solution was UNEXPECTEDLY SIMPLE.
96 We force DF flag on tunnels with preconfigured hop limit,
97 that is ALL. :-) Well, it does not remove the problem completely,
98 but exponential growth of network traffic is changed to linear
99 (branches, that exceed pmtu are pruned) and tunnel mtu
100 fastly degrades to value <68, where looping stops.
101 Yes, it is not good if there exists a router in the loop,
102 which does not force DF, even when encapsulating packets have DF set.
103 But it is not our problem! Nobody could accuse us, we made
104 all that we could make. Even if it is your gated who injected
105 fatal route to network, even if it were you who configured
106 fatal static route: you are innocent. :-)
107
108
109
110 3. Really, ipv4/ipip.c, ipv4/ip_gre.c and ipv6/sit.c contain
111 practically identical code. It would be good to glue them
112 together, but it is not very evident, how to make them modular.
113 sit is integral part of IPv6, ipip and gre are naturally modular.
114 We could extract common parts (hash table, ioctl etc)
115 to a separate module (ip_tunnel.c).
116
117 Alexey Kuznetsov.
118 */
119
Herbert Xuc19e6542008-10-09 11:59:55 -0700120static struct rtnl_link_ops ipgre_link_ops __read_mostly;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121static int ipgre_tunnel_init(struct net_device *dev);
122static void ipgre_tunnel_setup(struct net_device *dev);
Herbert Xu42aa9162008-10-09 11:59:32 -0700123static int ipgre_tunnel_bind_dev(struct net_device *dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124
125/* Fallback tunnel: no source, no destination, no key, no options */
126
Pavel Emelyanoveb8ce742008-04-16 01:10:26 -0700127#define HASH_SIZE 16
128
Eric Dumazetf99189b2009-11-17 10:42:49 +0000129static int ipgre_net_id __read_mostly;
Pavel Emelyanov59a4c752008-04-16 01:08:53 -0700130struct ipgre_net {
Pavel Emelyanoveb8ce742008-04-16 01:10:26 -0700131 struct ip_tunnel *tunnels[4][HASH_SIZE];
132
Pavel Emelyanov7daa0002008-04-16 01:10:05 -0700133 struct net_device *fb_tunnel_dev;
Pavel Emelyanov59a4c752008-04-16 01:08:53 -0700134};
135
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136/* Tunnel hash table */
137
138/*
139 4 hash tables:
140
141 3: (remote,local)
142 2: (remote,*)
143 1: (*,local)
144 0: (*,*)
145
146 We require exact key match i.e. if a key is present in packet
147 it will match only tunnel with the same key; if it is not present,
148 it will match only keyless tunnel.
149
150 All keysless packets, if not matched configured keyless tunnels
151 will match fallback tunnel.
152 */
153
Al Virod5a0a1e2006-11-08 00:23:14 -0800154#define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155
Pavel Emelyanoveb8ce742008-04-16 01:10:26 -0700156#define tunnels_r_l tunnels[3]
157#define tunnels_r tunnels[2]
158#define tunnels_l tunnels[1]
159#define tunnels_wc tunnels[0]
Eric Dumazet8d5b2c02009-10-23 06:14:38 +0000160/*
161 * Locking : hash tables are protected by RCU and a spinlock
162 */
163static DEFINE_SPINLOCK(ipgre_lock);
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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176 unsigned h0 = HASH(remote);
177 unsigned 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
Pavel Emelyanovf57e7d52008-04-16 01:09:22 -0700292static struct ip_tunnel **__ipgre_bucket(struct ipgre_net *ign,
293 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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298 unsigned h = HASH(key);
299 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
Pavel Emelyanovf57e7d52008-04-16 01:09:22 -0700311static inline struct ip_tunnel **ipgre_bucket(struct ipgre_net *ign,
312 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{
Pavel Emelyanovf57e7d52008-04-16 01:09:22 -0700319 struct ip_tunnel **tp = ipgre_bucket(ign, t);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320
Eric Dumazet8d5b2c02009-10-23 06:14:38 +0000321 spin_lock_bh(&ipgre_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322 t->next = *tp;
Eric Dumazet8d5b2c02009-10-23 06:14:38 +0000323 rcu_assign_pointer(*tp, t);
324 spin_unlock_bh(&ipgre_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325}
326
Pavel Emelyanovf57e7d52008-04-16 01:09:22 -0700327static void ipgre_tunnel_unlink(struct ipgre_net *ign, struct ip_tunnel *t)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328{
329 struct ip_tunnel **tp;
330
Pavel Emelyanovf57e7d52008-04-16 01:09:22 -0700331 for (tp = ipgre_bucket(ign, t); *tp; tp = &(*tp)->next) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 if (t == *tp) {
Eric Dumazet8d5b2c02009-10-23 06:14:38 +0000333 spin_lock_bh(&ipgre_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334 *tp = t->next;
Eric Dumazet8d5b2c02009-10-23 06:14:38 +0000335 spin_unlock_bh(&ipgre_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336 break;
337 }
338 }
339}
340
Herbert Xue1a80002008-10-09 12:00:17 -0700341static struct ip_tunnel *ipgre_tunnel_find(struct net *net,
342 struct ip_tunnel_parm *parms,
343 int type)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344{
Al Virod5a0a1e2006-11-08 00:23:14 -0800345 __be32 remote = parms->iph.daddr;
346 __be32 local = parms->iph.saddr;
347 __be32 key = parms->i_key;
Timo Teras749c10f2009-01-19 17:22:12 -0800348 int link = parms->link;
Herbert Xue1a80002008-10-09 12:00:17 -0700349 struct ip_tunnel *t, **tp;
350 struct ipgre_net *ign = net_generic(net, ipgre_net_id);
351
352 for (tp = __ipgre_bucket(ign, parms); (t = *tp) != NULL; tp = &t->next)
353 if (local == t->parms.iph.saddr &&
354 remote == t->parms.iph.daddr &&
355 key == t->parms.i_key &&
Timo Teras749c10f2009-01-19 17:22:12 -0800356 link == t->parms.link &&
Herbert Xue1a80002008-10-09 12:00:17 -0700357 type == t->dev->type)
358 break;
359
360 return t;
361}
362
363static struct ip_tunnel * ipgre_tunnel_locate(struct net *net,
364 struct ip_tunnel_parm *parms, int create)
365{
366 struct ip_tunnel *t, *nt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 struct net_device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 char name[IFNAMSIZ];
Pavel Emelyanovf57e7d52008-04-16 01:09:22 -0700369 struct ipgre_net *ign = net_generic(net, ipgre_net_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370
Herbert Xue1a80002008-10-09 12:00:17 -0700371 t = ipgre_tunnel_find(net, parms, ARPHRD_IPGRE);
372 if (t || !create)
373 return t;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374
375 if (parms->name[0])
376 strlcpy(name, parms->name, IFNAMSIZ);
Pavel Emelyanov34cc7ba2008-02-23 20:19:20 -0800377 else
378 sprintf(name, "gre%%d");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379
380 dev = alloc_netdev(sizeof(*t), name, ipgre_tunnel_setup);
381 if (!dev)
382 return NULL;
383
Pavel Emelyanov0b67ece2008-04-16 01:11:13 -0700384 dev_net_set(dev, net);
385
Pavel Emelyanovb37d428b2008-02-26 23:51:04 -0800386 if (strchr(name, '%')) {
387 if (dev_alloc_name(dev, name) < 0)
388 goto failed_free;
389 }
390
Patrick McHardy2941a482006-01-08 22:05:26 -0800391 nt = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 nt->parms = *parms;
Herbert Xuc19e6542008-10-09 11:59:55 -0700393 dev->rtnl_link_ops = &ipgre_link_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394
Herbert Xu42aa9162008-10-09 11:59:32 -0700395 dev->mtu = ipgre_tunnel_bind_dev(dev);
396
Pavel Emelyanovb37d428b2008-02-26 23:51:04 -0800397 if (register_netdevice(dev) < 0)
398 goto failed_free;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 dev_hold(dev);
Pavel Emelyanovf57e7d52008-04-16 01:09:22 -0700401 ipgre_tunnel_link(ign, nt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 return nt;
403
Pavel Emelyanovb37d428b2008-02-26 23:51:04 -0800404failed_free:
405 free_netdev(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 return NULL;
407}
408
409static void ipgre_tunnel_uninit(struct net_device *dev)
410{
Pavel Emelyanovf57e7d52008-04-16 01:09:22 -0700411 struct net *net = dev_net(dev);
412 struct ipgre_net *ign = net_generic(net, ipgre_net_id);
413
414 ipgre_tunnel_unlink(ign, netdev_priv(dev));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 dev_put(dev);
416}
417
418
419static void ipgre_err(struct sk_buff *skb, u32 info)
420{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421
Rami Rosen071f92d2008-05-21 17:47:54 -0700422/* All the routers (except for Linux) return only
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 8 bytes of packet payload. It means, that precise relaying of
424 ICMP in the real Internet is absolutely infeasible.
425
426 Moreover, Cisco "wise men" put GRE key to the third word
427 in GRE header. It makes impossible maintaining even soft state for keyed
428 GRE tunnels with enabled checksum. Tell them "thank you".
429
430 Well, I wonder, rfc1812 was written by Cisco employee,
431 what the hell these idiots break standrads established
432 by themself???
433 */
434
Jianjun Kong6ed25332008-11-03 00:25:16 -0800435 struct iphdr *iph = (struct iphdr *)skb->data;
Al Virod5a0a1e2006-11-08 00:23:14 -0800436 __be16 *p = (__be16*)(skb->data+(iph->ihl<<2));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 int grehlen = (iph->ihl<<2) + 4;
Arnaldo Carvalho de Melo88c76642007-03-13 14:43:18 -0300438 const int type = icmp_hdr(skb)->type;
439 const int code = icmp_hdr(skb)->code;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440 struct ip_tunnel *t;
Al Virod5a0a1e2006-11-08 00:23:14 -0800441 __be16 flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442
443 flags = p[0];
444 if (flags&(GRE_CSUM|GRE_KEY|GRE_SEQ|GRE_ROUTING|GRE_VERSION)) {
445 if (flags&(GRE_VERSION|GRE_ROUTING))
446 return;
447 if (flags&GRE_KEY) {
448 grehlen += 4;
449 if (flags&GRE_CSUM)
450 grehlen += 4;
451 }
452 }
453
454 /* If only 8 bytes returned, keyed message will be dropped here */
455 if (skb_headlen(skb) < grehlen)
456 return;
457
458 switch (type) {
459 default:
460 case ICMP_PARAMETERPROB:
461 return;
462
463 case ICMP_DEST_UNREACH:
464 switch (code) {
465 case ICMP_SR_FAILED:
466 case ICMP_PORT_UNREACH:
467 /* Impossible event. */
468 return;
469 case ICMP_FRAG_NEEDED:
470 /* Soft state for pmtu is maintained by IP core. */
471 return;
472 default:
473 /* All others are translated to HOST_UNREACH.
474 rfc2003 contains "deep thoughts" about NET_UNREACH,
475 I believe they are just ether pollution. --ANK
476 */
477 break;
478 }
479 break;
480 case ICMP_TIME_EXCEEDED:
481 if (code != ICMP_EXC_TTL)
482 return;
483 break;
484 }
485
Eric Dumazet8d5b2c02009-10-23 06:14:38 +0000486 rcu_read_lock();
Timo Teras749c10f2009-01-19 17:22:12 -0800487 t = ipgre_tunnel_lookup(skb->dev, iph->daddr, iph->saddr,
Herbert Xue1a80002008-10-09 12:00:17 -0700488 flags & GRE_KEY ?
489 *(((__be32 *)p) + (grehlen / 4) - 1) : 0,
490 p[1]);
Joe Perchesf97c1e02007-12-16 13:45:43 -0800491 if (t == NULL || t->parms.iph.daddr == 0 ||
492 ipv4_is_multicast(t->parms.iph.daddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 goto out;
494
495 if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED)
496 goto out;
497
Wei Yongjunda6185d82009-02-24 23:34:48 -0800498 if (time_before(jiffies, t->err_time + IPTUNNEL_ERR_TIMEO))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 t->err_count++;
500 else
501 t->err_count = 1;
502 t->err_time = jiffies;
503out:
Eric Dumazet8d5b2c02009-10-23 06:14:38 +0000504 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505}
506
507static inline void ipgre_ecn_decapsulate(struct iphdr *iph, struct sk_buff *skb)
508{
509 if (INET_ECN_is_ce(iph->tos)) {
510 if (skb->protocol == htons(ETH_P_IP)) {
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700511 IP_ECN_set_ce(ip_hdr(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 } else if (skb->protocol == htons(ETH_P_IPV6)) {
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700513 IP6_ECN_set_ce(ipv6_hdr(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 }
515 }
516}
517
518static inline u8
519ipgre_ecn_encapsulate(u8 tos, struct iphdr *old_iph, struct sk_buff *skb)
520{
521 u8 inner = 0;
522 if (skb->protocol == htons(ETH_P_IP))
523 inner = old_iph->tos;
524 else if (skb->protocol == htons(ETH_P_IPV6))
525 inner = ipv6_get_dsfield((struct ipv6hdr *)old_iph);
526 return INET_ECN_encapsulate(tos, inner);
527}
528
529static int ipgre_rcv(struct sk_buff *skb)
530{
531 struct iphdr *iph;
532 u8 *h;
Al Virod5a0a1e2006-11-08 00:23:14 -0800533 __be16 flags;
Al Virod3bc23e2006-11-14 21:24:49 -0800534 __sum16 csum = 0;
Al Virod5a0a1e2006-11-08 00:23:14 -0800535 __be32 key = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536 u32 seqno = 0;
537 struct ip_tunnel *tunnel;
538 int offset = 4;
Herbert Xue1a80002008-10-09 12:00:17 -0700539 __be16 gre_proto;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540
541 if (!pskb_may_pull(skb, 16))
542 goto drop_nolock;
543
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700544 iph = ip_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 h = skb->data;
Al Virod5a0a1e2006-11-08 00:23:14 -0800546 flags = *(__be16*)h;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547
548 if (flags&(GRE_CSUM|GRE_KEY|GRE_ROUTING|GRE_SEQ|GRE_VERSION)) {
549 /* - Version must be 0.
550 - We do not support routing headers.
551 */
552 if (flags&(GRE_VERSION|GRE_ROUTING))
553 goto drop_nolock;
554
555 if (flags&GRE_CSUM) {
Herbert Xufb286bb2005-11-10 13:01:24 -0800556 switch (skb->ip_summed) {
Patrick McHardy84fa7932006-08-29 16:44:56 -0700557 case CHECKSUM_COMPLETE:
Al Virod3bc23e2006-11-14 21:24:49 -0800558 csum = csum_fold(skb->csum);
Herbert Xufb286bb2005-11-10 13:01:24 -0800559 if (!csum)
560 break;
561 /* fall through */
562 case CHECKSUM_NONE:
563 skb->csum = 0;
564 csum = __skb_checksum_complete(skb);
Patrick McHardy84fa7932006-08-29 16:44:56 -0700565 skb->ip_summed = CHECKSUM_COMPLETE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 }
567 offset += 4;
568 }
569 if (flags&GRE_KEY) {
Al Virod5a0a1e2006-11-08 00:23:14 -0800570 key = *(__be32*)(h + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 offset += 4;
572 }
573 if (flags&GRE_SEQ) {
Al Virod5a0a1e2006-11-08 00:23:14 -0800574 seqno = ntohl(*(__be32*)(h + offset));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 offset += 4;
576 }
577 }
578
Herbert Xue1a80002008-10-09 12:00:17 -0700579 gre_proto = *(__be16 *)(h + 2);
580
Eric Dumazet8d5b2c02009-10-23 06:14:38 +0000581 rcu_read_lock();
Timo Teras749c10f2009-01-19 17:22:12 -0800582 if ((tunnel = ipgre_tunnel_lookup(skb->dev,
Herbert Xue1a80002008-10-09 12:00:17 -0700583 iph->saddr, iph->daddr, key,
584 gre_proto))) {
Pavel Emelyanovaddd68e2008-05-21 14:14:22 -0700585 struct net_device_stats *stats = &tunnel->dev->stats;
586
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 secpath_reset(skb);
588
Herbert Xue1a80002008-10-09 12:00:17 -0700589 skb->protocol = gre_proto;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 /* WCCP version 1 and 2 protocol decoding.
591 * - Change protocol to IP
592 * - When dealing with WCCPv2, Skip extra 4 bytes in GRE header
593 */
Herbert Xue1a80002008-10-09 12:00:17 -0700594 if (flags == 0 && gre_proto == htons(ETH_P_WCCP)) {
YOSHIFUJI Hideaki496c98d2006-10-10 19:41:21 -0700595 skb->protocol = htons(ETH_P_IP);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900596 if ((*(h + offset) & 0xF0) != 0x40)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 offset += 4;
598 }
599
Timo Teras1d069162007-12-20 00:10:33 -0800600 skb->mac_header = skb->network_header;
Arnaldo Carvalho de Melo4209fb62007-03-10 18:42:03 -0300601 __pskb_pull(skb, offset);
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -0700602 skb_postpull_rcsum(skb, skb_transport_header(skb), offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603 skb->pkt_type = PACKET_HOST;
604#ifdef CONFIG_NET_IPGRE_BROADCAST
Joe Perchesf97c1e02007-12-16 13:45:43 -0800605 if (ipv4_is_multicast(iph->daddr)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 /* Looped back packet, drop it! */
Eric Dumazet511c3f92009-06-02 05:14:27 +0000607 if (skb_rtable(skb)->fl.iif == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608 goto drop;
Pavel Emelyanovaddd68e2008-05-21 14:14:22 -0700609 stats->multicast++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 skb->pkt_type = PACKET_BROADCAST;
611 }
612#endif
613
614 if (((flags&GRE_CSUM) && csum) ||
615 (!(flags&GRE_CSUM) && tunnel->parms.i_flags&GRE_CSUM)) {
Pavel Emelyanovaddd68e2008-05-21 14:14:22 -0700616 stats->rx_crc_errors++;
617 stats->rx_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 goto drop;
619 }
620 if (tunnel->parms.i_flags&GRE_SEQ) {
621 if (!(flags&GRE_SEQ) ||
622 (tunnel->i_seqno && (s32)(seqno - tunnel->i_seqno) < 0)) {
Pavel Emelyanovaddd68e2008-05-21 14:14:22 -0700623 stats->rx_fifo_errors++;
624 stats->rx_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 goto drop;
626 }
627 tunnel->i_seqno = seqno + 1;
628 }
Herbert Xue1a80002008-10-09 12:00:17 -0700629
630 /* Warning: All skb pointers will be invalidated! */
631 if (tunnel->dev->type == ARPHRD_ETHER) {
632 if (!pskb_may_pull(skb, ETH_HLEN)) {
633 stats->rx_length_errors++;
634 stats->rx_errors++;
635 goto drop;
636 }
637
638 iph = ip_hdr(skb);
639 skb->protocol = eth_type_trans(skb, tunnel->dev);
640 skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN);
641 }
642
Eric Dumazetd19d56d2010-05-17 22:36:55 -0700643 skb_tunnel_rx(skb, tunnel->dev);
Herbert Xue1a80002008-10-09 12:00:17 -0700644
645 skb_reset_network_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 ipgre_ecn_decapsulate(iph, skb);
Herbert Xue1a80002008-10-09 12:00:17 -0700647
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 netif_rx(skb);
Eric Dumazet8d5b2c02009-10-23 06:14:38 +0000649 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 return(0);
651 }
Herbert Xu45af08b2006-04-05 22:31:19 -0700652 icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653
654drop:
Eric Dumazet8d5b2c02009-10-23 06:14:38 +0000655 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656drop_nolock:
657 kfree_skb(skb);
658 return(0);
659}
660
Stephen Hemminger6fef4c02009-08-31 19:50:41 +0000661static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662{
Patrick McHardy2941a482006-01-08 22:05:26 -0800663 struct ip_tunnel *tunnel = netdev_priv(dev);
Eric Dumazet0bfbedb2009-10-05 00:11:22 -0700664 struct net_device_stats *stats = &dev->stats;
665 struct netdev_queue *txq = netdev_get_tx_queue(dev, 0);
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700666 struct iphdr *old_iph = ip_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 struct iphdr *tiph;
668 u8 tos;
Al Virod5a0a1e2006-11-08 00:23:14 -0800669 __be16 df;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 struct rtable *rt; /* Route to the other host */
671 struct net_device *tdev; /* Device to other host */
672 struct iphdr *iph; /* Our new IP header */
Chuck Leverc2636b42007-10-23 21:07:32 -0700673 unsigned int max_headroom; /* The extra header space needed */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 int gre_hlen;
Al Virod5a0a1e2006-11-08 00:23:14 -0800675 __be32 dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 int mtu;
677
Herbert Xue1a80002008-10-09 12:00:17 -0700678 if (dev->type == ARPHRD_ETHER)
679 IPCB(skb)->flags = 0;
680
681 if (dev->header_ops && dev->type == ARPHRD_IPGRE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 gre_hlen = 0;
Jianjun Kong6ed25332008-11-03 00:25:16 -0800683 tiph = (struct iphdr *)skb->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 } else {
685 gre_hlen = tunnel->hlen;
686 tiph = &tunnel->parms.iph;
687 }
688
689 if ((dst = tiph->daddr) == 0) {
690 /* NBMA tunnel */
691
Eric Dumazetadf30902009-06-02 05:19:30 +0000692 if (skb_dst(skb) == NULL) {
Pavel Emelyanovaddd68e2008-05-21 14:14:22 -0700693 stats->tx_fifo_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 goto tx_error;
695 }
696
697 if (skb->protocol == htons(ETH_P_IP)) {
Eric Dumazet511c3f92009-06-02 05:14:27 +0000698 rt = skb_rtable(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 if ((dst = rt->rt_gateway) == 0)
700 goto tx_error_icmp;
701 }
702#ifdef CONFIG_IPV6
703 else if (skb->protocol == htons(ETH_P_IPV6)) {
704 struct in6_addr *addr6;
705 int addr_type;
Eric Dumazetadf30902009-06-02 05:19:30 +0000706 struct neighbour *neigh = skb_dst(skb)->neighbour;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707
708 if (neigh == NULL)
709 goto tx_error;
710
Jianjun Kong6ed25332008-11-03 00:25:16 -0800711 addr6 = (struct in6_addr *)&neigh->primary_key;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 addr_type = ipv6_addr_type(addr6);
713
714 if (addr_type == IPV6_ADDR_ANY) {
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700715 addr6 = &ipv6_hdr(skb)->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 addr_type = ipv6_addr_type(addr6);
717 }
718
719 if ((addr_type & IPV6_ADDR_COMPATv4) == 0)
720 goto tx_error_icmp;
721
722 dst = addr6->s6_addr32[3];
723 }
724#endif
725 else
726 goto tx_error;
727 }
728
729 tos = tiph->tos;
Andreas Jaggiee686ca2009-07-14 09:35:59 -0700730 if (tos == 1) {
731 tos = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 if (skb->protocol == htons(ETH_P_IP))
733 tos = old_iph->tos;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 }
735
736 {
737 struct flowi fl = { .oif = tunnel->parms.link,
738 .nl_u = { .ip4_u =
739 { .daddr = dst,
740 .saddr = tiph->saddr,
741 .tos = RT_TOS(tos) } },
742 .proto = IPPROTO_GRE };
Pavel Emelyanov96635522008-04-16 01:10:44 -0700743 if (ip_route_output_key(dev_net(dev), &rt, &fl)) {
Pavel Emelyanovaddd68e2008-05-21 14:14:22 -0700744 stats->tx_carrier_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 goto tx_error;
746 }
747 }
Changli Gaod8d1f302010-06-10 23:31:35 -0700748 tdev = rt->dst.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749
750 if (tdev == dev) {
751 ip_rt_put(rt);
Pavel Emelyanovaddd68e2008-05-21 14:14:22 -0700752 stats->collisions++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 goto tx_error;
754 }
755
756 df = tiph->frag_off;
757 if (df)
Changli Gaod8d1f302010-06-10 23:31:35 -0700758 mtu = dst_mtu(&rt->dst) - dev->hard_header_len - tunnel->hlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 else
Eric Dumazetadf30902009-06-02 05:19:30 +0000760 mtu = skb_dst(skb) ? dst_mtu(skb_dst(skb)) : dev->mtu;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761
Eric Dumazetadf30902009-06-02 05:19:30 +0000762 if (skb_dst(skb))
763 skb_dst(skb)->ops->update_pmtu(skb_dst(skb), mtu);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764
765 if (skb->protocol == htons(ETH_P_IP)) {
766 df |= (old_iph->frag_off&htons(IP_DF));
767
768 if ((old_iph->frag_off&htons(IP_DF)) &&
769 mtu < ntohs(old_iph->tot_len)) {
770 icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));
771 ip_rt_put(rt);
772 goto tx_error;
773 }
774 }
775#ifdef CONFIG_IPV6
776 else if (skb->protocol == htons(ETH_P_IPV6)) {
Eric Dumazetadf30902009-06-02 05:19:30 +0000777 struct rt6_info *rt6 = (struct rt6_info *)skb_dst(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778
Eric Dumazetadf30902009-06-02 05:19:30 +0000779 if (rt6 && mtu < dst_mtu(skb_dst(skb)) && mtu >= IPV6_MIN_MTU) {
Joe Perchesf97c1e02007-12-16 13:45:43 -0800780 if ((tunnel->parms.iph.daddr &&
781 !ipv4_is_multicast(tunnel->parms.iph.daddr)) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 rt6->rt6i_dst.plen == 128) {
783 rt6->rt6i_flags |= RTF_MODIFIED;
Eric Dumazetadf30902009-06-02 05:19:30 +0000784 skb_dst(skb)->metrics[RTAX_MTU-1] = mtu;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 }
786 }
787
788 if (mtu >= IPV6_MIN_MTU && mtu < skb->len - tunnel->hlen + gre_hlen) {
Alexey Dobriyan3ffe5332010-02-18 08:25:24 +0000789 icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 ip_rt_put(rt);
791 goto tx_error;
792 }
793 }
794#endif
795
796 if (tunnel->err_count > 0) {
Wei Yongjunda6185d82009-02-24 23:34:48 -0800797 if (time_before(jiffies,
798 tunnel->err_time + IPTUNNEL_ERR_TIMEO)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 tunnel->err_count--;
800
801 dst_link_failure(skb);
802 } else
803 tunnel->err_count = 0;
804 }
805
Changli Gaod8d1f302010-06-10 23:31:35 -0700806 max_headroom = LL_RESERVED_SPACE(tdev) + gre_hlen + rt->dst.header_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807
Patrick McHardycfbba492007-07-09 15:33:40 -0700808 if (skb_headroom(skb) < max_headroom || skb_shared(skb)||
809 (skb_cloned(skb) && !skb_clone_writable(skb, 0))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom);
Timo Teräs243aad82010-03-20 02:27:58 +0000811 if (max_headroom > dev->needed_headroom)
812 dev->needed_headroom = max_headroom;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 if (!new_skb) {
814 ip_rt_put(rt);
Eric Dumazet0bfbedb2009-10-05 00:11:22 -0700815 txq->tx_dropped++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 dev_kfree_skb(skb);
Patrick McHardy6ed10652009-06-23 06:03:08 +0000817 return NETDEV_TX_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 }
819 if (skb->sk)
820 skb_set_owner_w(new_skb, skb->sk);
821 dev_kfree_skb(skb);
822 skb = new_skb;
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700823 old_iph = ip_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 }
825
Herbert Xu64194c32008-10-09 12:03:17 -0700826 skb_reset_transport_header(skb);
Arnaldo Carvalho de Meloe2d1bca2007-04-10 20:46:21 -0700827 skb_push(skb, gre_hlen);
828 skb_reset_network_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
Patrick McHardy48d5cad2006-02-15 15:10:22 -0800830 IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED |
831 IPSKB_REROUTED);
Eric Dumazetadf30902009-06-02 05:19:30 +0000832 skb_dst_drop(skb);
Changli Gaod8d1f302010-06-10 23:31:35 -0700833 skb_dst_set(skb, &rt->dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834
835 /*
836 * Push down and install the IPIP header.
837 */
838
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700839 iph = ip_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 iph->version = 4;
841 iph->ihl = sizeof(struct iphdr) >> 2;
842 iph->frag_off = df;
843 iph->protocol = IPPROTO_GRE;
844 iph->tos = ipgre_ecn_encapsulate(tos, old_iph, skb);
845 iph->daddr = rt->rt_dst;
846 iph->saddr = rt->rt_src;
847
848 if ((iph->ttl = tiph->ttl) == 0) {
849 if (skb->protocol == htons(ETH_P_IP))
850 iph->ttl = old_iph->ttl;
851#ifdef CONFIG_IPV6
852 else if (skb->protocol == htons(ETH_P_IPV6))
Jianjun Kong6ed25332008-11-03 00:25:16 -0800853 iph->ttl = ((struct ipv6hdr *)old_iph)->hop_limit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854#endif
855 else
Changli Gaod8d1f302010-06-10 23:31:35 -0700856 iph->ttl = dst_metric(&rt->dst, RTAX_HOPLIMIT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 }
858
Herbert Xue1a80002008-10-09 12:00:17 -0700859 ((__be16 *)(iph + 1))[0] = tunnel->parms.o_flags;
860 ((__be16 *)(iph + 1))[1] = (dev->type == ARPHRD_ETHER) ?
861 htons(ETH_P_TEB) : skb->protocol;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862
863 if (tunnel->parms.o_flags&(GRE_KEY|GRE_CSUM|GRE_SEQ)) {
Al Virod5a0a1e2006-11-08 00:23:14 -0800864 __be32 *ptr = (__be32*)(((u8*)iph) + tunnel->hlen - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865
866 if (tunnel->parms.o_flags&GRE_SEQ) {
867 ++tunnel->o_seqno;
868 *ptr = htonl(tunnel->o_seqno);
869 ptr--;
870 }
871 if (tunnel->parms.o_flags&GRE_KEY) {
872 *ptr = tunnel->parms.o_key;
873 ptr--;
874 }
875 if (tunnel->parms.o_flags&GRE_CSUM) {
876 *ptr = 0;
Al Viro5f92a732006-11-14 21:36:54 -0800877 *(__sum16*)ptr = ip_compute_csum((void*)(iph+1), skb->len - sizeof(struct iphdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 }
879 }
880
881 nf_reset(skb);
882
883 IPTUNNEL_XMIT();
Patrick McHardy6ed10652009-06-23 06:03:08 +0000884 return NETDEV_TX_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885
886tx_error_icmp:
887 dst_link_failure(skb);
888
889tx_error:
890 stats->tx_errors++;
891 dev_kfree_skb(skb);
Patrick McHardy6ed10652009-06-23 06:03:08 +0000892 return NETDEV_TX_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893}
894
Herbert Xu42aa9162008-10-09 11:59:32 -0700895static int ipgre_tunnel_bind_dev(struct net_device *dev)
Michal Schmidtee34c1e2007-12-13 09:46:32 -0800896{
897 struct net_device *tdev = NULL;
898 struct ip_tunnel *tunnel;
899 struct iphdr *iph;
900 int hlen = LL_MAX_HEADER;
901 int mtu = ETH_DATA_LEN;
902 int addend = sizeof(struct iphdr) + 4;
903
904 tunnel = netdev_priv(dev);
905 iph = &tunnel->parms.iph;
906
Herbert Xuc95b8192008-10-09 11:58:54 -0700907 /* Guess output device to choose reasonable mtu and needed_headroom */
Michal Schmidtee34c1e2007-12-13 09:46:32 -0800908
909 if (iph->daddr) {
910 struct flowi fl = { .oif = tunnel->parms.link,
911 .nl_u = { .ip4_u =
912 { .daddr = iph->daddr,
913 .saddr = iph->saddr,
914 .tos = RT_TOS(iph->tos) } },
915 .proto = IPPROTO_GRE };
916 struct rtable *rt;
Pavel Emelyanov96635522008-04-16 01:10:44 -0700917 if (!ip_route_output_key(dev_net(dev), &rt, &fl)) {
Changli Gaod8d1f302010-06-10 23:31:35 -0700918 tdev = rt->dst.dev;
Michal Schmidtee34c1e2007-12-13 09:46:32 -0800919 ip_rt_put(rt);
920 }
Herbert Xue1a80002008-10-09 12:00:17 -0700921
922 if (dev->type != ARPHRD_ETHER)
923 dev->flags |= IFF_POINTOPOINT;
Michal Schmidtee34c1e2007-12-13 09:46:32 -0800924 }
925
926 if (!tdev && tunnel->parms.link)
Pavel Emelyanov96635522008-04-16 01:10:44 -0700927 tdev = __dev_get_by_index(dev_net(dev), tunnel->parms.link);
Michal Schmidtee34c1e2007-12-13 09:46:32 -0800928
929 if (tdev) {
Herbert Xuc95b8192008-10-09 11:58:54 -0700930 hlen = tdev->hard_header_len + tdev->needed_headroom;
Michal Schmidtee34c1e2007-12-13 09:46:32 -0800931 mtu = tdev->mtu;
932 }
933 dev->iflink = tunnel->parms.link;
934
935 /* Precalculate GRE options length */
936 if (tunnel->parms.o_flags&(GRE_CSUM|GRE_KEY|GRE_SEQ)) {
937 if (tunnel->parms.o_flags&GRE_CSUM)
938 addend += 4;
939 if (tunnel->parms.o_flags&GRE_KEY)
940 addend += 4;
941 if (tunnel->parms.o_flags&GRE_SEQ)
942 addend += 4;
943 }
Herbert Xuc95b8192008-10-09 11:58:54 -0700944 dev->needed_headroom = addend + hlen;
Tom Goff8cdb0452009-08-14 16:33:56 -0700945 mtu -= dev->hard_header_len + addend;
Herbert Xu42aa9162008-10-09 11:59:32 -0700946
947 if (mtu < 68)
948 mtu = 68;
949
Michal Schmidtee34c1e2007-12-13 09:46:32 -0800950 tunnel->hlen = addend;
951
Herbert Xu42aa9162008-10-09 11:59:32 -0700952 return mtu;
Michal Schmidtee34c1e2007-12-13 09:46:32 -0800953}
954
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955static int
956ipgre_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
957{
958 int err = 0;
959 struct ip_tunnel_parm p;
960 struct ip_tunnel *t;
Pavel Emelyanovf57e7d52008-04-16 01:09:22 -0700961 struct net *net = dev_net(dev);
962 struct ipgre_net *ign = net_generic(net, ipgre_net_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963
964 switch (cmd) {
965 case SIOCGETTUNNEL:
966 t = NULL;
Pavel Emelyanov7daa0002008-04-16 01:10:05 -0700967 if (dev == ign->fb_tunnel_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) {
969 err = -EFAULT;
970 break;
971 }
Pavel Emelyanovf57e7d52008-04-16 01:09:22 -0700972 t = ipgre_tunnel_locate(net, &p, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973 }
974 if (t == NULL)
Patrick McHardy2941a482006-01-08 22:05:26 -0800975 t = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 memcpy(&p, &t->parms, sizeof(p));
977 if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p)))
978 err = -EFAULT;
979 break;
980
981 case SIOCADDTUNNEL:
982 case SIOCCHGTUNNEL:
983 err = -EPERM;
984 if (!capable(CAP_NET_ADMIN))
985 goto done;
986
987 err = -EFAULT;
988 if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
989 goto done;
990
991 err = -EINVAL;
992 if (p.iph.version != 4 || p.iph.protocol != IPPROTO_GRE ||
993 p.iph.ihl != 5 || (p.iph.frag_off&htons(~IP_DF)) ||
994 ((p.i_flags|p.o_flags)&(GRE_VERSION|GRE_ROUTING)))
995 goto done;
996 if (p.iph.ttl)
997 p.iph.frag_off |= htons(IP_DF);
998
999 if (!(p.i_flags&GRE_KEY))
1000 p.i_key = 0;
1001 if (!(p.o_flags&GRE_KEY))
1002 p.o_key = 0;
1003
Pavel Emelyanovf57e7d52008-04-16 01:09:22 -07001004 t = ipgre_tunnel_locate(net, &p, cmd == SIOCADDTUNNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005
Pavel Emelyanov7daa0002008-04-16 01:10:05 -07001006 if (dev != ign->fb_tunnel_dev && cmd == SIOCCHGTUNNEL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 if (t != NULL) {
1008 if (t->dev != dev) {
1009 err = -EEXIST;
1010 break;
1011 }
1012 } else {
Jianjun Kong6ed25332008-11-03 00:25:16 -08001013 unsigned nflags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014
Patrick McHardy2941a482006-01-08 22:05:26 -08001015 t = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016
Joe Perchesf97c1e02007-12-16 13:45:43 -08001017 if (ipv4_is_multicast(p.iph.daddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018 nflags = IFF_BROADCAST;
1019 else if (p.iph.daddr)
1020 nflags = IFF_POINTOPOINT;
1021
1022 if ((dev->flags^nflags)&(IFF_POINTOPOINT|IFF_BROADCAST)) {
1023 err = -EINVAL;
1024 break;
1025 }
Pavel Emelyanovf57e7d52008-04-16 01:09:22 -07001026 ipgre_tunnel_unlink(ign, t);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027 t->parms.iph.saddr = p.iph.saddr;
1028 t->parms.iph.daddr = p.iph.daddr;
1029 t->parms.i_key = p.i_key;
1030 t->parms.o_key = p.o_key;
1031 memcpy(dev->dev_addr, &p.iph.saddr, 4);
1032 memcpy(dev->broadcast, &p.iph.daddr, 4);
Pavel Emelyanovf57e7d52008-04-16 01:09:22 -07001033 ipgre_tunnel_link(ign, t);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034 netdev_state_change(dev);
1035 }
1036 }
1037
1038 if (t) {
1039 err = 0;
1040 if (cmd == SIOCCHGTUNNEL) {
1041 t->parms.iph.ttl = p.iph.ttl;
1042 t->parms.iph.tos = p.iph.tos;
1043 t->parms.iph.frag_off = p.iph.frag_off;
Michal Schmidtee34c1e2007-12-13 09:46:32 -08001044 if (t->parms.link != p.link) {
1045 t->parms.link = p.link;
Herbert Xu42aa9162008-10-09 11:59:32 -07001046 dev->mtu = ipgre_tunnel_bind_dev(dev);
Michal Schmidtee34c1e2007-12-13 09:46:32 -08001047 netdev_state_change(dev);
1048 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049 }
1050 if (copy_to_user(ifr->ifr_ifru.ifru_data, &t->parms, sizeof(p)))
1051 err = -EFAULT;
1052 } else
1053 err = (cmd == SIOCADDTUNNEL ? -ENOBUFS : -ENOENT);
1054 break;
1055
1056 case SIOCDELTUNNEL:
1057 err = -EPERM;
1058 if (!capable(CAP_NET_ADMIN))
1059 goto done;
1060
Pavel Emelyanov7daa0002008-04-16 01:10:05 -07001061 if (dev == ign->fb_tunnel_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 err = -EFAULT;
1063 if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
1064 goto done;
1065 err = -ENOENT;
Pavel Emelyanovf57e7d52008-04-16 01:09:22 -07001066 if ((t = ipgre_tunnel_locate(net, &p, 0)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067 goto done;
1068 err = -EPERM;
Pavel Emelyanov7daa0002008-04-16 01:10:05 -07001069 if (t == netdev_priv(ign->fb_tunnel_dev))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 goto done;
1071 dev = t->dev;
1072 }
Stephen Hemminger22f8cde2007-02-07 00:09:58 -08001073 unregister_netdevice(dev);
1074 err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075 break;
1076
1077 default:
1078 err = -EINVAL;
1079 }
1080
1081done:
1082 return err;
1083}
1084
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085static int ipgre_tunnel_change_mtu(struct net_device *dev, int new_mtu)
1086{
Patrick McHardy2941a482006-01-08 22:05:26 -08001087 struct ip_tunnel *tunnel = netdev_priv(dev);
Herbert Xuc95b8192008-10-09 11:58:54 -07001088 if (new_mtu < 68 ||
1089 new_mtu > 0xFFF8 - dev->hard_header_len - tunnel->hlen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090 return -EINVAL;
1091 dev->mtu = new_mtu;
1092 return 0;
1093}
1094
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095/* Nice toy. Unfortunately, useless in real life :-)
1096 It allows to construct virtual multiprotocol broadcast "LAN"
1097 over the Internet, provided multicast routing is tuned.
1098
1099
1100 I have no idea was this bicycle invented before me,
1101 so that I had to set ARPHRD_IPGRE to a random value.
1102 I have an impression, that Cisco could make something similar,
1103 but this feature is apparently missing in IOS<=11.2(8).
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001104
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 I set up 10.66.66/24 and fec0:6666:6666::0/96 as virtual networks
1106 with broadcast 224.66.66.66. If you have access to mbone, play with me :-)
1107
1108 ping -t 255 224.66.66.66
1109
1110 If nobody answers, mbone does not work.
1111
1112 ip tunnel add Universe mode gre remote 224.66.66.66 local <Your_real_addr> ttl 255
1113 ip addr add 10.66.66.<somewhat>/24 dev Universe
1114 ifconfig Universe up
1115 ifconfig Universe add fe80::<Your_real_addr>/10
1116 ifconfig Universe add fec0:6666:6666::<Your_real_addr>/96
1117 ftp 10.66.66.66
1118 ...
1119 ftp fec0:6666:6666::193.233.7.65
1120 ...
1121
1122 */
1123
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -07001124static int ipgre_header(struct sk_buff *skb, struct net_device *dev,
1125 unsigned short type,
1126 const void *daddr, const void *saddr, unsigned len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127{
Patrick McHardy2941a482006-01-08 22:05:26 -08001128 struct ip_tunnel *t = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129 struct iphdr *iph = (struct iphdr *)skb_push(skb, t->hlen);
Al Virod5a0a1e2006-11-08 00:23:14 -08001130 __be16 *p = (__be16*)(iph+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131
1132 memcpy(iph, &t->parms.iph, sizeof(struct iphdr));
1133 p[0] = t->parms.o_flags;
1134 p[1] = htons(type);
1135
1136 /*
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001137 * Set the source hardware address.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138 */
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001139
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140 if (saddr)
1141 memcpy(&iph->saddr, saddr, 4);
Timo Teräs6d55cb92010-03-03 04:01:13 +00001142 if (daddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143 memcpy(&iph->daddr, daddr, 4);
Timo Teräs6d55cb92010-03-03 04:01:13 +00001144 if (iph->daddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145 return t->hlen;
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001146
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147 return -t->hlen;
1148}
1149
Timo Teras6a5f44d2007-10-23 20:31:53 -07001150static int ipgre_header_parse(const struct sk_buff *skb, unsigned char *haddr)
1151{
Jianjun Kong6ed25332008-11-03 00:25:16 -08001152 struct iphdr *iph = (struct iphdr *) skb_mac_header(skb);
Timo Teras6a5f44d2007-10-23 20:31:53 -07001153 memcpy(haddr, &iph->saddr, 4);
1154 return 4;
1155}
1156
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -07001157static const struct header_ops ipgre_header_ops = {
1158 .create = ipgre_header,
Timo Teras6a5f44d2007-10-23 20:31:53 -07001159 .parse = ipgre_header_parse,
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -07001160};
1161
Timo Teras6a5f44d2007-10-23 20:31:53 -07001162#ifdef CONFIG_NET_IPGRE_BROADCAST
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163static int ipgre_open(struct net_device *dev)
1164{
Patrick McHardy2941a482006-01-08 22:05:26 -08001165 struct ip_tunnel *t = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166
Joe Perchesf97c1e02007-12-16 13:45:43 -08001167 if (ipv4_is_multicast(t->parms.iph.daddr)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168 struct flowi fl = { .oif = t->parms.link,
1169 .nl_u = { .ip4_u =
1170 { .daddr = t->parms.iph.daddr,
1171 .saddr = t->parms.iph.saddr,
1172 .tos = RT_TOS(t->parms.iph.tos) } },
1173 .proto = IPPROTO_GRE };
1174 struct rtable *rt;
Pavel Emelyanov96635522008-04-16 01:10:44 -07001175 if (ip_route_output_key(dev_net(dev), &rt, &fl))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176 return -EADDRNOTAVAIL;
Changli Gaod8d1f302010-06-10 23:31:35 -07001177 dev = rt->dst.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178 ip_rt_put(rt);
Herbert Xue5ed6392005-10-03 14:35:55 -07001179 if (__in_dev_get_rtnl(dev) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180 return -EADDRNOTAVAIL;
1181 t->mlink = dev->ifindex;
Herbert Xue5ed6392005-10-03 14:35:55 -07001182 ip_mc_inc_group(__in_dev_get_rtnl(dev), t->parms.iph.daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183 }
1184 return 0;
1185}
1186
1187static int ipgre_close(struct net_device *dev)
1188{
Patrick McHardy2941a482006-01-08 22:05:26 -08001189 struct ip_tunnel *t = netdev_priv(dev);
Stephen Hemmingerb8c26a32008-11-20 20:34:29 -08001190
Joe Perchesf97c1e02007-12-16 13:45:43 -08001191 if (ipv4_is_multicast(t->parms.iph.daddr) && t->mlink) {
Denis V. Lunev7fee0ca2008-01-21 17:32:38 -08001192 struct in_device *in_dev;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001193 in_dev = inetdev_by_index(dev_net(dev), t->mlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194 if (in_dev) {
1195 ip_mc_dec_group(in_dev, t->parms.iph.daddr);
1196 in_dev_put(in_dev);
1197 }
1198 }
1199 return 0;
1200}
1201
1202#endif
1203
Stephen Hemmingerb8c26a32008-11-20 20:34:29 -08001204static const struct net_device_ops ipgre_netdev_ops = {
1205 .ndo_init = ipgre_tunnel_init,
1206 .ndo_uninit = ipgre_tunnel_uninit,
1207#ifdef CONFIG_NET_IPGRE_BROADCAST
1208 .ndo_open = ipgre_open,
1209 .ndo_stop = ipgre_close,
1210#endif
1211 .ndo_start_xmit = ipgre_tunnel_xmit,
1212 .ndo_do_ioctl = ipgre_tunnel_ioctl,
1213 .ndo_change_mtu = ipgre_tunnel_change_mtu,
1214};
1215
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216static void ipgre_tunnel_setup(struct net_device *dev)
1217{
Stephen Hemmingerb8c26a32008-11-20 20:34:29 -08001218 dev->netdev_ops = &ipgre_netdev_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219 dev->destructor = free_netdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220
1221 dev->type = ARPHRD_IPGRE;
Herbert Xuc95b8192008-10-09 11:58:54 -07001222 dev->needed_headroom = LL_MAX_HEADER + sizeof(struct iphdr) + 4;
Kris Katterjohn46f25df2006-01-05 16:35:42 -08001223 dev->mtu = ETH_DATA_LEN - sizeof(struct iphdr) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224 dev->flags = IFF_NOARP;
1225 dev->iflink = 0;
1226 dev->addr_len = 4;
Pavel Emelyanov0b67ece2008-04-16 01:11:13 -07001227 dev->features |= NETIF_F_NETNS_LOCAL;
Eric Dumazet108bfa82009-05-28 22:35:10 +00001228 dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229}
1230
1231static int ipgre_tunnel_init(struct net_device *dev)
1232{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233 struct ip_tunnel *tunnel;
1234 struct iphdr *iph;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235
Patrick McHardy2941a482006-01-08 22:05:26 -08001236 tunnel = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237 iph = &tunnel->parms.iph;
1238
1239 tunnel->dev = dev;
1240 strcpy(tunnel->parms.name, dev->name);
1241
1242 memcpy(dev->dev_addr, &tunnel->parms.iph.saddr, 4);
1243 memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4);
1244
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245 if (iph->daddr) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246#ifdef CONFIG_NET_IPGRE_BROADCAST
Joe Perchesf97c1e02007-12-16 13:45:43 -08001247 if (ipv4_is_multicast(iph->daddr)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248 if (!iph->saddr)
1249 return -EINVAL;
1250 dev->flags = IFF_BROADCAST;
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -07001251 dev->header_ops = &ipgre_header_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252 }
1253#endif
Michal Schmidtee34c1e2007-12-13 09:46:32 -08001254 } else
Timo Teras6a5f44d2007-10-23 20:31:53 -07001255 dev->header_ops = &ipgre_header_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257 return 0;
1258}
1259
Stephen Hemmingerb8c26a32008-11-20 20:34:29 -08001260static void ipgre_fb_tunnel_init(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261{
Patrick McHardy2941a482006-01-08 22:05:26 -08001262 struct ip_tunnel *tunnel = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263 struct iphdr *iph = &tunnel->parms.iph;
Pavel Emelyanoveb8ce742008-04-16 01:10:26 -07001264 struct ipgre_net *ign = net_generic(dev_net(dev), ipgre_net_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265
1266 tunnel->dev = dev;
1267 strcpy(tunnel->parms.name, dev->name);
1268
1269 iph->version = 4;
1270 iph->protocol = IPPROTO_GRE;
1271 iph->ihl = 5;
1272 tunnel->hlen = sizeof(struct iphdr) + 4;
1273
1274 dev_hold(dev);
Pavel Emelyanoveb8ce742008-04-16 01:10:26 -07001275 ign->tunnels_wc[0] = tunnel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276}
1277
1278
Alexey Dobriyan32613092009-09-14 12:21:47 +00001279static const struct net_protocol ipgre_protocol = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280 .handler = ipgre_rcv,
1281 .err_handler = ipgre_err,
Pavel Emelyanovf96c1482008-04-16 01:11:36 -07001282 .netns_ok = 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283};
1284
Eric Dumazeteef6dd62009-10-27 07:07:16 +00001285static void ipgre_destroy_tunnels(struct ipgre_net *ign, struct list_head *head)
Pavel Emelyanoveb8ce742008-04-16 01:10:26 -07001286{
1287 int prio;
1288
1289 for (prio = 0; prio < 4; prio++) {
1290 int h;
1291 for (h = 0; h < HASH_SIZE; h++) {
Eric Dumazeteef6dd62009-10-27 07:07:16 +00001292 struct ip_tunnel *t = ign->tunnels[prio][h];
1293
1294 while (t != NULL) {
1295 unregister_netdevice_queue(t->dev, head);
1296 t = t->next;
1297 }
Pavel Emelyanoveb8ce742008-04-16 01:10:26 -07001298 }
1299 }
1300}
1301
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00001302static int __net_init ipgre_init_net(struct net *net)
Pavel Emelyanov59a4c752008-04-16 01:08:53 -07001303{
Eric W. Biedermancfb8fbf2009-11-29 15:46:13 +00001304 struct ipgre_net *ign = net_generic(net, ipgre_net_id);
Pavel Emelyanov59a4c752008-04-16 01:08:53 -07001305 int err;
Pavel Emelyanov59a4c752008-04-16 01:08:53 -07001306
Pavel Emelyanov7daa0002008-04-16 01:10:05 -07001307 ign->fb_tunnel_dev = alloc_netdev(sizeof(struct ip_tunnel), "gre0",
1308 ipgre_tunnel_setup);
1309 if (!ign->fb_tunnel_dev) {
1310 err = -ENOMEM;
1311 goto err_alloc_dev;
1312 }
Alexey Dobriyanbe77e592008-11-23 17:26:26 -08001313 dev_net_set(ign->fb_tunnel_dev, net);
Pavel Emelyanov7daa0002008-04-16 01:10:05 -07001314
Stephen Hemmingerb8c26a32008-11-20 20:34:29 -08001315 ipgre_fb_tunnel_init(ign->fb_tunnel_dev);
Herbert Xuc19e6542008-10-09 11:59:55 -07001316 ign->fb_tunnel_dev->rtnl_link_ops = &ipgre_link_ops;
Pavel Emelyanov7daa0002008-04-16 01:10:05 -07001317
1318 if ((err = register_netdev(ign->fb_tunnel_dev)))
1319 goto err_reg_dev;
1320
Pavel Emelyanov59a4c752008-04-16 01:08:53 -07001321 return 0;
1322
Pavel Emelyanov7daa0002008-04-16 01:10:05 -07001323err_reg_dev:
1324 free_netdev(ign->fb_tunnel_dev);
1325err_alloc_dev:
Pavel Emelyanov59a4c752008-04-16 01:08:53 -07001326 return err;
1327}
1328
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00001329static void __net_exit ipgre_exit_net(struct net *net)
Pavel Emelyanov59a4c752008-04-16 01:08:53 -07001330{
1331 struct ipgre_net *ign;
Eric Dumazeteef6dd62009-10-27 07:07:16 +00001332 LIST_HEAD(list);
Pavel Emelyanov59a4c752008-04-16 01:08:53 -07001333
1334 ign = net_generic(net, ipgre_net_id);
Pavel Emelyanov7daa0002008-04-16 01:10:05 -07001335 rtnl_lock();
Eric Dumazeteef6dd62009-10-27 07:07:16 +00001336 ipgre_destroy_tunnels(ign, &list);
1337 unregister_netdevice_many(&list);
Pavel Emelyanov7daa0002008-04-16 01:10:05 -07001338 rtnl_unlock();
Pavel Emelyanov59a4c752008-04-16 01:08:53 -07001339}
1340
1341static struct pernet_operations ipgre_net_ops = {
1342 .init = ipgre_init_net,
1343 .exit = ipgre_exit_net,
Eric W. Biedermancfb8fbf2009-11-29 15:46:13 +00001344 .id = &ipgre_net_id,
1345 .size = sizeof(struct ipgre_net),
Pavel Emelyanov59a4c752008-04-16 01:08:53 -07001346};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347
Herbert Xuc19e6542008-10-09 11:59:55 -07001348static int ipgre_tunnel_validate(struct nlattr *tb[], struct nlattr *data[])
1349{
1350 __be16 flags;
1351
1352 if (!data)
1353 return 0;
1354
1355 flags = 0;
1356 if (data[IFLA_GRE_IFLAGS])
1357 flags |= nla_get_be16(data[IFLA_GRE_IFLAGS]);
1358 if (data[IFLA_GRE_OFLAGS])
1359 flags |= nla_get_be16(data[IFLA_GRE_OFLAGS]);
1360 if (flags & (GRE_VERSION|GRE_ROUTING))
1361 return -EINVAL;
1362
1363 return 0;
1364}
1365
Herbert Xue1a80002008-10-09 12:00:17 -07001366static int ipgre_tap_validate(struct nlattr *tb[], struct nlattr *data[])
1367{
1368 __be32 daddr;
1369
1370 if (tb[IFLA_ADDRESS]) {
1371 if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN)
1372 return -EINVAL;
1373 if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS])))
1374 return -EADDRNOTAVAIL;
1375 }
1376
1377 if (!data)
1378 goto out;
1379
1380 if (data[IFLA_GRE_REMOTE]) {
1381 memcpy(&daddr, nla_data(data[IFLA_GRE_REMOTE]), 4);
1382 if (!daddr)
1383 return -EINVAL;
1384 }
1385
1386out:
1387 return ipgre_tunnel_validate(tb, data);
1388}
1389
Herbert Xuc19e6542008-10-09 11:59:55 -07001390static void ipgre_netlink_parms(struct nlattr *data[],
1391 struct ip_tunnel_parm *parms)
1392{
Herbert Xu7bb82d92008-10-11 12:20:15 -07001393 memset(parms, 0, sizeof(*parms));
Herbert Xuc19e6542008-10-09 11:59:55 -07001394
1395 parms->iph.protocol = IPPROTO_GRE;
1396
1397 if (!data)
1398 return;
1399
1400 if (data[IFLA_GRE_LINK])
1401 parms->link = nla_get_u32(data[IFLA_GRE_LINK]);
1402
1403 if (data[IFLA_GRE_IFLAGS])
1404 parms->i_flags = nla_get_be16(data[IFLA_GRE_IFLAGS]);
1405
1406 if (data[IFLA_GRE_OFLAGS])
1407 parms->o_flags = nla_get_be16(data[IFLA_GRE_OFLAGS]);
1408
1409 if (data[IFLA_GRE_IKEY])
1410 parms->i_key = nla_get_be32(data[IFLA_GRE_IKEY]);
1411
1412 if (data[IFLA_GRE_OKEY])
1413 parms->o_key = nla_get_be32(data[IFLA_GRE_OKEY]);
1414
1415 if (data[IFLA_GRE_LOCAL])
Patrick McHardy4d74f8b2008-10-10 12:11:06 -07001416 parms->iph.saddr = nla_get_be32(data[IFLA_GRE_LOCAL]);
Herbert Xuc19e6542008-10-09 11:59:55 -07001417
1418 if (data[IFLA_GRE_REMOTE])
Patrick McHardy4d74f8b2008-10-10 12:11:06 -07001419 parms->iph.daddr = nla_get_be32(data[IFLA_GRE_REMOTE]);
Herbert Xuc19e6542008-10-09 11:59:55 -07001420
1421 if (data[IFLA_GRE_TTL])
1422 parms->iph.ttl = nla_get_u8(data[IFLA_GRE_TTL]);
1423
1424 if (data[IFLA_GRE_TOS])
1425 parms->iph.tos = nla_get_u8(data[IFLA_GRE_TOS]);
1426
1427 if (!data[IFLA_GRE_PMTUDISC] || nla_get_u8(data[IFLA_GRE_PMTUDISC]))
1428 parms->iph.frag_off = htons(IP_DF);
1429}
1430
Herbert Xue1a80002008-10-09 12:00:17 -07001431static int ipgre_tap_init(struct net_device *dev)
1432{
1433 struct ip_tunnel *tunnel;
1434
1435 tunnel = netdev_priv(dev);
1436
1437 tunnel->dev = dev;
1438 strcpy(tunnel->parms.name, dev->name);
1439
1440 ipgre_tunnel_bind_dev(dev);
1441
1442 return 0;
1443}
1444
Stephen Hemmingerb8c26a32008-11-20 20:34:29 -08001445static const struct net_device_ops ipgre_tap_netdev_ops = {
1446 .ndo_init = ipgre_tap_init,
1447 .ndo_uninit = ipgre_tunnel_uninit,
1448 .ndo_start_xmit = ipgre_tunnel_xmit,
1449 .ndo_set_mac_address = eth_mac_addr,
1450 .ndo_validate_addr = eth_validate_addr,
1451 .ndo_change_mtu = ipgre_tunnel_change_mtu,
1452};
1453
Herbert Xue1a80002008-10-09 12:00:17 -07001454static void ipgre_tap_setup(struct net_device *dev)
1455{
1456
1457 ether_setup(dev);
1458
Herbert Xu2e9526b2009-10-30 05:51:48 +00001459 dev->netdev_ops = &ipgre_tap_netdev_ops;
Herbert Xue1a80002008-10-09 12:00:17 -07001460 dev->destructor = free_netdev;
Herbert Xue1a80002008-10-09 12:00:17 -07001461
1462 dev->iflink = 0;
1463 dev->features |= NETIF_F_NETNS_LOCAL;
1464}
1465
Eric W. Biederman81adee42009-11-08 00:53:51 -08001466static int ipgre_newlink(struct net *src_net, struct net_device *dev, struct nlattr *tb[],
Herbert Xuc19e6542008-10-09 11:59:55 -07001467 struct nlattr *data[])
1468{
1469 struct ip_tunnel *nt;
1470 struct net *net = dev_net(dev);
1471 struct ipgre_net *ign = net_generic(net, ipgre_net_id);
1472 int mtu;
1473 int err;
1474
1475 nt = netdev_priv(dev);
1476 ipgre_netlink_parms(data, &nt->parms);
1477
Herbert Xue1a80002008-10-09 12:00:17 -07001478 if (ipgre_tunnel_find(net, &nt->parms, dev->type))
Herbert Xuc19e6542008-10-09 11:59:55 -07001479 return -EEXIST;
1480
Herbert Xue1a80002008-10-09 12:00:17 -07001481 if (dev->type == ARPHRD_ETHER && !tb[IFLA_ADDRESS])
1482 random_ether_addr(dev->dev_addr);
1483
Herbert Xuc19e6542008-10-09 11:59:55 -07001484 mtu = ipgre_tunnel_bind_dev(dev);
1485 if (!tb[IFLA_MTU])
1486 dev->mtu = mtu;
1487
1488 err = register_netdevice(dev);
1489 if (err)
1490 goto out;
1491
1492 dev_hold(dev);
1493 ipgre_tunnel_link(ign, nt);
1494
1495out:
1496 return err;
1497}
1498
1499static int ipgre_changelink(struct net_device *dev, struct nlattr *tb[],
1500 struct nlattr *data[])
1501{
1502 struct ip_tunnel *t, *nt;
1503 struct net *net = dev_net(dev);
1504 struct ipgre_net *ign = net_generic(net, ipgre_net_id);
1505 struct ip_tunnel_parm p;
1506 int mtu;
1507
1508 if (dev == ign->fb_tunnel_dev)
1509 return -EINVAL;
1510
1511 nt = netdev_priv(dev);
1512 ipgre_netlink_parms(data, &p);
1513
1514 t = ipgre_tunnel_locate(net, &p, 0);
1515
1516 if (t) {
1517 if (t->dev != dev)
1518 return -EEXIST;
1519 } else {
Herbert Xuc19e6542008-10-09 11:59:55 -07001520 t = nt;
1521
Herbert Xu2e9526b2009-10-30 05:51:48 +00001522 if (dev->type != ARPHRD_ETHER) {
1523 unsigned nflags = 0;
Herbert Xuc19e6542008-10-09 11:59:55 -07001524
Herbert Xu2e9526b2009-10-30 05:51:48 +00001525 if (ipv4_is_multicast(p.iph.daddr))
1526 nflags = IFF_BROADCAST;
1527 else if (p.iph.daddr)
1528 nflags = IFF_POINTOPOINT;
1529
1530 if ((dev->flags ^ nflags) &
1531 (IFF_POINTOPOINT | IFF_BROADCAST))
1532 return -EINVAL;
1533 }
Herbert Xuc19e6542008-10-09 11:59:55 -07001534
1535 ipgre_tunnel_unlink(ign, t);
1536 t->parms.iph.saddr = p.iph.saddr;
1537 t->parms.iph.daddr = p.iph.daddr;
1538 t->parms.i_key = p.i_key;
Herbert Xu2e9526b2009-10-30 05:51:48 +00001539 if (dev->type != ARPHRD_ETHER) {
1540 memcpy(dev->dev_addr, &p.iph.saddr, 4);
1541 memcpy(dev->broadcast, &p.iph.daddr, 4);
1542 }
Herbert Xuc19e6542008-10-09 11:59:55 -07001543 ipgre_tunnel_link(ign, t);
1544 netdev_state_change(dev);
1545 }
1546
1547 t->parms.o_key = p.o_key;
1548 t->parms.iph.ttl = p.iph.ttl;
1549 t->parms.iph.tos = p.iph.tos;
1550 t->parms.iph.frag_off = p.iph.frag_off;
1551
1552 if (t->parms.link != p.link) {
1553 t->parms.link = p.link;
1554 mtu = ipgre_tunnel_bind_dev(dev);
1555 if (!tb[IFLA_MTU])
1556 dev->mtu = mtu;
1557 netdev_state_change(dev);
1558 }
1559
1560 return 0;
1561}
1562
1563static size_t ipgre_get_size(const struct net_device *dev)
1564{
1565 return
1566 /* IFLA_GRE_LINK */
1567 nla_total_size(4) +
1568 /* IFLA_GRE_IFLAGS */
1569 nla_total_size(2) +
1570 /* IFLA_GRE_OFLAGS */
1571 nla_total_size(2) +
1572 /* IFLA_GRE_IKEY */
1573 nla_total_size(4) +
1574 /* IFLA_GRE_OKEY */
1575 nla_total_size(4) +
1576 /* IFLA_GRE_LOCAL */
1577 nla_total_size(4) +
1578 /* IFLA_GRE_REMOTE */
1579 nla_total_size(4) +
1580 /* IFLA_GRE_TTL */
1581 nla_total_size(1) +
1582 /* IFLA_GRE_TOS */
1583 nla_total_size(1) +
1584 /* IFLA_GRE_PMTUDISC */
1585 nla_total_size(1) +
1586 0;
1587}
1588
1589static int ipgre_fill_info(struct sk_buff *skb, const struct net_device *dev)
1590{
1591 struct ip_tunnel *t = netdev_priv(dev);
1592 struct ip_tunnel_parm *p = &t->parms;
1593
1594 NLA_PUT_U32(skb, IFLA_GRE_LINK, p->link);
1595 NLA_PUT_BE16(skb, IFLA_GRE_IFLAGS, p->i_flags);
1596 NLA_PUT_BE16(skb, IFLA_GRE_OFLAGS, p->o_flags);
Patrick McHardyba9e64b2008-10-10 12:10:30 -07001597 NLA_PUT_BE32(skb, IFLA_GRE_IKEY, p->i_key);
1598 NLA_PUT_BE32(skb, IFLA_GRE_OKEY, p->o_key);
Patrick McHardy4d74f8b2008-10-10 12:11:06 -07001599 NLA_PUT_BE32(skb, IFLA_GRE_LOCAL, p->iph.saddr);
1600 NLA_PUT_BE32(skb, IFLA_GRE_REMOTE, p->iph.daddr);
Herbert Xuc19e6542008-10-09 11:59:55 -07001601 NLA_PUT_U8(skb, IFLA_GRE_TTL, p->iph.ttl);
1602 NLA_PUT_U8(skb, IFLA_GRE_TOS, p->iph.tos);
1603 NLA_PUT_U8(skb, IFLA_GRE_PMTUDISC, !!(p->iph.frag_off & htons(IP_DF)));
1604
1605 return 0;
1606
1607nla_put_failure:
1608 return -EMSGSIZE;
1609}
1610
1611static const struct nla_policy ipgre_policy[IFLA_GRE_MAX + 1] = {
1612 [IFLA_GRE_LINK] = { .type = NLA_U32 },
1613 [IFLA_GRE_IFLAGS] = { .type = NLA_U16 },
1614 [IFLA_GRE_OFLAGS] = { .type = NLA_U16 },
1615 [IFLA_GRE_IKEY] = { .type = NLA_U32 },
1616 [IFLA_GRE_OKEY] = { .type = NLA_U32 },
Patrick McHardy4d74f8b2008-10-10 12:11:06 -07001617 [IFLA_GRE_LOCAL] = { .len = FIELD_SIZEOF(struct iphdr, saddr) },
1618 [IFLA_GRE_REMOTE] = { .len = FIELD_SIZEOF(struct iphdr, daddr) },
Herbert Xuc19e6542008-10-09 11:59:55 -07001619 [IFLA_GRE_TTL] = { .type = NLA_U8 },
1620 [IFLA_GRE_TOS] = { .type = NLA_U8 },
1621 [IFLA_GRE_PMTUDISC] = { .type = NLA_U8 },
1622};
1623
1624static struct rtnl_link_ops ipgre_link_ops __read_mostly = {
1625 .kind = "gre",
1626 .maxtype = IFLA_GRE_MAX,
1627 .policy = ipgre_policy,
1628 .priv_size = sizeof(struct ip_tunnel),
1629 .setup = ipgre_tunnel_setup,
1630 .validate = ipgre_tunnel_validate,
1631 .newlink = ipgre_newlink,
1632 .changelink = ipgre_changelink,
1633 .get_size = ipgre_get_size,
1634 .fill_info = ipgre_fill_info,
1635};
1636
Herbert Xue1a80002008-10-09 12:00:17 -07001637static struct rtnl_link_ops ipgre_tap_ops __read_mostly = {
1638 .kind = "gretap",
1639 .maxtype = IFLA_GRE_MAX,
1640 .policy = ipgre_policy,
1641 .priv_size = sizeof(struct ip_tunnel),
1642 .setup = ipgre_tap_setup,
1643 .validate = ipgre_tap_validate,
1644 .newlink = ipgre_newlink,
1645 .changelink = ipgre_changelink,
1646 .get_size = ipgre_get_size,
1647 .fill_info = ipgre_fill_info,
1648};
1649
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650/*
1651 * And now the modules code and kernel interface.
1652 */
1653
1654static int __init ipgre_init(void)
1655{
1656 int err;
1657
1658 printk(KERN_INFO "GRE over IPv4 tunneling driver\n");
1659
Eric W. Biedermancfb8fbf2009-11-29 15:46:13 +00001660 err = register_pernet_device(&ipgre_net_ops);
Pavel Emelyanov59a4c752008-04-16 01:08:53 -07001661 if (err < 0)
Alexey Dobriyanc2892f02010-02-16 07:57:44 +00001662 return err;
1663
1664 err = inet_add_protocol(&ipgre_protocol, IPPROTO_GRE);
1665 if (err < 0) {
1666 printk(KERN_INFO "ipgre init: can't add protocol\n");
1667 goto add_proto_failed;
1668 }
Pavel Emelyanov7daa0002008-04-16 01:10:05 -07001669
Herbert Xuc19e6542008-10-09 11:59:55 -07001670 err = rtnl_link_register(&ipgre_link_ops);
1671 if (err < 0)
1672 goto rtnl_link_failed;
1673
Herbert Xue1a80002008-10-09 12:00:17 -07001674 err = rtnl_link_register(&ipgre_tap_ops);
1675 if (err < 0)
1676 goto tap_ops_failed;
1677
Herbert Xuc19e6542008-10-09 11:59:55 -07001678out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679 return err;
Herbert Xuc19e6542008-10-09 11:59:55 -07001680
Herbert Xue1a80002008-10-09 12:00:17 -07001681tap_ops_failed:
1682 rtnl_link_unregister(&ipgre_link_ops);
Herbert Xuc19e6542008-10-09 11:59:55 -07001683rtnl_link_failed:
Herbert Xuc19e6542008-10-09 11:59:55 -07001684 inet_del_protocol(&ipgre_protocol, IPPROTO_GRE);
Alexey Dobriyanc2892f02010-02-16 07:57:44 +00001685add_proto_failed:
1686 unregister_pernet_device(&ipgre_net_ops);
Herbert Xuc19e6542008-10-09 11:59:55 -07001687 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001688}
1689
Alexey Kuznetsovdb445752005-07-30 17:46:44 -07001690static void __exit ipgre_fini(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691{
Herbert Xue1a80002008-10-09 12:00:17 -07001692 rtnl_link_unregister(&ipgre_tap_ops);
Herbert Xuc19e6542008-10-09 11:59:55 -07001693 rtnl_link_unregister(&ipgre_link_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694 if (inet_del_protocol(&ipgre_protocol, IPPROTO_GRE) < 0)
1695 printk(KERN_INFO "ipgre close: can't remove protocol\n");
Alexey Dobriyanc2892f02010-02-16 07:57:44 +00001696 unregister_pernet_device(&ipgre_net_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697}
1698
1699module_init(ipgre_init);
1700module_exit(ipgre_fini);
1701MODULE_LICENSE("GPL");
Patrick McHardy4d74f8b2008-10-10 12:11:06 -07001702MODULE_ALIAS_RTNL_LINK("gre");
1703MODULE_ALIAS_RTNL_LINK("gretap");