blob: 85176895495a790329fd9c8ba863f6092322d7ac [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 {
Pavel Emelyanoveb8ce742008-04-16 01:10:26 -0700132 struct ip_tunnel *tunnels[4][HASH_SIZE];
133
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/*
162 * Locking : hash tables are protected by RCU and a spinlock
163 */
164static DEFINE_SPINLOCK(ipgre_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165
Eric Dumazet8d5b2c02009-10-23 06:14:38 +0000166#define for_each_ip_tunnel_rcu(start) \
167 for (t = rcu_dereference(start); t; t = rcu_dereference(t->next))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168
169/* Given src, dst and key, find appropriate for input tunnel. */
170
Timo Teras749c10f2009-01-19 17:22:12 -0800171static struct ip_tunnel * ipgre_tunnel_lookup(struct net_device *dev,
Herbert Xue1a80002008-10-09 12:00:17 -0700172 __be32 remote, __be32 local,
173 __be32 key, __be16 gre_proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174{
Timo Teras749c10f2009-01-19 17:22:12 -0800175 struct net *net = dev_net(dev);
176 int link = dev->ifindex;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177 unsigned h0 = HASH(remote);
178 unsigned h1 = HASH(key);
Timo Terasafcf1242009-01-26 20:56:10 -0800179 struct ip_tunnel *t, *cand = NULL;
Pavel Emelyanov7daa0002008-04-16 01:10:05 -0700180 struct ipgre_net *ign = net_generic(net, ipgre_net_id);
Herbert Xue1a80002008-10-09 12:00:17 -0700181 int dev_type = (gre_proto == htons(ETH_P_TEB)) ?
182 ARPHRD_ETHER : ARPHRD_IPGRE;
Timo Terasafcf1242009-01-26 20:56:10 -0800183 int score, cand_score = 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184
Eric Dumazet8d5b2c02009-10-23 06:14:38 +0000185 for_each_ip_tunnel_rcu(ign->tunnels_r_l[h0 ^ h1]) {
Timo Teras749c10f2009-01-19 17:22:12 -0800186 if (local != t->parms.iph.saddr ||
187 remote != t->parms.iph.daddr ||
188 key != t->parms.i_key ||
189 !(t->dev->flags & IFF_UP))
190 continue;
191
192 if (t->dev->type != ARPHRD_IPGRE &&
193 t->dev->type != dev_type)
194 continue;
195
Timo Terasafcf1242009-01-26 20:56:10 -0800196 score = 0;
Timo Teras749c10f2009-01-19 17:22:12 -0800197 if (t->parms.link != link)
Timo Terasafcf1242009-01-26 20:56:10 -0800198 score |= 1;
Timo Teras749c10f2009-01-19 17:22:12 -0800199 if (t->dev->type != dev_type)
Timo Terasafcf1242009-01-26 20:56:10 -0800200 score |= 2;
201 if (score == 0)
Timo Teras749c10f2009-01-19 17:22:12 -0800202 return t;
Timo Terasafcf1242009-01-26 20:56:10 -0800203
204 if (score < cand_score) {
205 cand = t;
206 cand_score = score;
207 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 }
Herbert Xue1a80002008-10-09 12:00:17 -0700209
Eric Dumazet8d5b2c02009-10-23 06:14:38 +0000210 for_each_ip_tunnel_rcu(ign->tunnels_r[h0 ^ h1]) {
Timo Teras749c10f2009-01-19 17:22:12 -0800211 if (remote != t->parms.iph.daddr ||
212 key != t->parms.i_key ||
213 !(t->dev->flags & IFF_UP))
214 continue;
215
216 if (t->dev->type != ARPHRD_IPGRE &&
217 t->dev->type != dev_type)
218 continue;
219
Timo Terasafcf1242009-01-26 20:56:10 -0800220 score = 0;
Timo Teras749c10f2009-01-19 17:22:12 -0800221 if (t->parms.link != link)
Timo Terasafcf1242009-01-26 20:56:10 -0800222 score |= 1;
Timo Teras749c10f2009-01-19 17:22:12 -0800223 if (t->dev->type != dev_type)
Timo Terasafcf1242009-01-26 20:56:10 -0800224 score |= 2;
225 if (score == 0)
Timo Teras749c10f2009-01-19 17:22:12 -0800226 return t;
Timo Terasafcf1242009-01-26 20:56:10 -0800227
228 if (score < cand_score) {
229 cand = t;
230 cand_score = score;
231 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232 }
Herbert Xue1a80002008-10-09 12:00:17 -0700233
Eric Dumazet8d5b2c02009-10-23 06:14:38 +0000234 for_each_ip_tunnel_rcu(ign->tunnels_l[h1]) {
Timo Teras749c10f2009-01-19 17:22:12 -0800235 if ((local != t->parms.iph.saddr &&
236 (local != t->parms.iph.daddr ||
237 !ipv4_is_multicast(local))) ||
238 key != t->parms.i_key ||
239 !(t->dev->flags & IFF_UP))
240 continue;
241
242 if (t->dev->type != ARPHRD_IPGRE &&
243 t->dev->type != dev_type)
244 continue;
245
Timo Terasafcf1242009-01-26 20:56:10 -0800246 score = 0;
Timo Teras749c10f2009-01-19 17:22:12 -0800247 if (t->parms.link != link)
Timo Terasafcf1242009-01-26 20:56:10 -0800248 score |= 1;
Timo Teras749c10f2009-01-19 17:22:12 -0800249 if (t->dev->type != dev_type)
Timo Terasafcf1242009-01-26 20:56:10 -0800250 score |= 2;
251 if (score == 0)
Timo Teras749c10f2009-01-19 17:22:12 -0800252 return t;
Timo Terasafcf1242009-01-26 20:56:10 -0800253
254 if (score < cand_score) {
255 cand = t;
256 cand_score = score;
257 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 }
Herbert Xue1a80002008-10-09 12:00:17 -0700259
Eric Dumazet8d5b2c02009-10-23 06:14:38 +0000260 for_each_ip_tunnel_rcu(ign->tunnels_wc[h1]) {
Timo Teras749c10f2009-01-19 17:22:12 -0800261 if (t->parms.i_key != key ||
262 !(t->dev->flags & IFF_UP))
263 continue;
264
265 if (t->dev->type != ARPHRD_IPGRE &&
266 t->dev->type != dev_type)
267 continue;
268
Timo Terasafcf1242009-01-26 20:56:10 -0800269 score = 0;
Timo Teras749c10f2009-01-19 17:22:12 -0800270 if (t->parms.link != link)
Timo Terasafcf1242009-01-26 20:56:10 -0800271 score |= 1;
Timo Teras749c10f2009-01-19 17:22:12 -0800272 if (t->dev->type != dev_type)
Timo Terasafcf1242009-01-26 20:56:10 -0800273 score |= 2;
274 if (score == 0)
Timo Teras749c10f2009-01-19 17:22:12 -0800275 return t;
Timo Terasafcf1242009-01-26 20:56:10 -0800276
277 if (score < cand_score) {
278 cand = t;
279 cand_score = score;
280 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281 }
282
Timo Terasafcf1242009-01-26 20:56:10 -0800283 if (cand != NULL)
284 return cand;
Herbert Xue1a80002008-10-09 12:00:17 -0700285
Eric Dumazet8d5b2c02009-10-23 06:14:38 +0000286 dev = ign->fb_tunnel_dev;
287 if (dev->flags & IFF_UP)
288 return netdev_priv(dev);
Timo Teras749c10f2009-01-19 17:22:12 -0800289
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290 return NULL;
291}
292
Pavel Emelyanovf57e7d52008-04-16 01:09:22 -0700293static struct ip_tunnel **__ipgre_bucket(struct ipgre_net *ign,
294 struct ip_tunnel_parm *parms)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295{
YOSHIFUJI Hideaki5056a1e2007-04-24 20:44:48 +0900296 __be32 remote = parms->iph.daddr;
297 __be32 local = parms->iph.saddr;
298 __be32 key = parms->i_key;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 unsigned h = HASH(key);
300 int prio = 0;
301
302 if (local)
303 prio |= 1;
Joe Perchesf97c1e02007-12-16 13:45:43 -0800304 if (remote && !ipv4_is_multicast(remote)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305 prio |= 2;
306 h ^= HASH(remote);
307 }
308
Pavel Emelyanoveb8ce742008-04-16 01:10:26 -0700309 return &ign->tunnels[prio][h];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310}
311
Pavel Emelyanovf57e7d52008-04-16 01:09:22 -0700312static inline struct ip_tunnel **ipgre_bucket(struct ipgre_net *ign,
313 struct ip_tunnel *t)
YOSHIFUJI Hideaki5056a1e2007-04-24 20:44:48 +0900314{
Pavel Emelyanovf57e7d52008-04-16 01:09:22 -0700315 return __ipgre_bucket(ign, &t->parms);
YOSHIFUJI Hideaki5056a1e2007-04-24 20:44:48 +0900316}
317
Pavel Emelyanovf57e7d52008-04-16 01:09:22 -0700318static void ipgre_tunnel_link(struct ipgre_net *ign, struct ip_tunnel *t)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319{
Pavel Emelyanovf57e7d52008-04-16 01:09:22 -0700320 struct ip_tunnel **tp = ipgre_bucket(ign, t);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321
Eric Dumazet8d5b2c02009-10-23 06:14:38 +0000322 spin_lock_bh(&ipgre_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323 t->next = *tp;
Eric Dumazet8d5b2c02009-10-23 06:14:38 +0000324 rcu_assign_pointer(*tp, t);
325 spin_unlock_bh(&ipgre_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326}
327
Pavel Emelyanovf57e7d52008-04-16 01:09:22 -0700328static void ipgre_tunnel_unlink(struct ipgre_net *ign, struct ip_tunnel *t)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329{
330 struct ip_tunnel **tp;
331
Pavel Emelyanovf57e7d52008-04-16 01:09:22 -0700332 for (tp = ipgre_bucket(ign, t); *tp; tp = &(*tp)->next) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 if (t == *tp) {
Eric Dumazet8d5b2c02009-10-23 06:14:38 +0000334 spin_lock_bh(&ipgre_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335 *tp = t->next;
Eric Dumazet8d5b2c02009-10-23 06:14:38 +0000336 spin_unlock_bh(&ipgre_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 break;
338 }
339 }
340}
341
Herbert Xue1a80002008-10-09 12:00:17 -0700342static struct ip_tunnel *ipgre_tunnel_find(struct net *net,
343 struct ip_tunnel_parm *parms,
344 int type)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345{
Al Virod5a0a1e2006-11-08 00:23:14 -0800346 __be32 remote = parms->iph.daddr;
347 __be32 local = parms->iph.saddr;
348 __be32 key = parms->i_key;
Timo Teras749c10f2009-01-19 17:22:12 -0800349 int link = parms->link;
Herbert Xue1a80002008-10-09 12:00:17 -0700350 struct ip_tunnel *t, **tp;
351 struct ipgre_net *ign = net_generic(net, ipgre_net_id);
352
353 for (tp = __ipgre_bucket(ign, parms); (t = *tp) != NULL; tp = &t->next)
354 if (local == t->parms.iph.saddr &&
355 remote == t->parms.iph.daddr &&
356 key == t->parms.i_key &&
Timo Teras749c10f2009-01-19 17:22:12 -0800357 link == t->parms.link &&
Herbert Xue1a80002008-10-09 12:00:17 -0700358 type == t->dev->type)
359 break;
360
361 return t;
362}
363
364static struct ip_tunnel * ipgre_tunnel_locate(struct net *net,
365 struct ip_tunnel_parm *parms, int create)
366{
367 struct ip_tunnel *t, *nt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 struct net_device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 char name[IFNAMSIZ];
Pavel Emelyanovf57e7d52008-04-16 01:09:22 -0700370 struct ipgre_net *ign = net_generic(net, ipgre_net_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371
Herbert Xue1a80002008-10-09 12:00:17 -0700372 t = ipgre_tunnel_find(net, parms, ARPHRD_IPGRE);
373 if (t || !create)
374 return t;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375
376 if (parms->name[0])
377 strlcpy(name, parms->name, IFNAMSIZ);
Pavel Emelyanov34cc7ba2008-02-23 20:19:20 -0800378 else
379 sprintf(name, "gre%%d");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380
381 dev = alloc_netdev(sizeof(*t), name, ipgre_tunnel_setup);
382 if (!dev)
383 return NULL;
384
Pavel Emelyanov0b67ece2008-04-16 01:11:13 -0700385 dev_net_set(dev, net);
386
Pavel Emelyanovb37d428b2008-02-26 23:51:04 -0800387 if (strchr(name, '%')) {
388 if (dev_alloc_name(dev, name) < 0)
389 goto failed_free;
390 }
391
Patrick McHardy2941a482006-01-08 22:05:26 -0800392 nt = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 nt->parms = *parms;
Herbert Xuc19e6542008-10-09 11:59:55 -0700394 dev->rtnl_link_ops = &ipgre_link_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395
Herbert Xu42aa9162008-10-09 11:59:32 -0700396 dev->mtu = ipgre_tunnel_bind_dev(dev);
397
Pavel Emelyanovb37d428b2008-02-26 23:51:04 -0800398 if (register_netdevice(dev) < 0)
399 goto failed_free;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 dev_hold(dev);
Pavel Emelyanovf57e7d52008-04-16 01:09:22 -0700402 ipgre_tunnel_link(ign, nt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 return nt;
404
Pavel Emelyanovb37d428b2008-02-26 23:51:04 -0800405failed_free:
406 free_netdev(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 return NULL;
408}
409
410static void ipgre_tunnel_uninit(struct net_device *dev)
411{
Pavel Emelyanovf57e7d52008-04-16 01:09:22 -0700412 struct net *net = dev_net(dev);
413 struct ipgre_net *ign = net_generic(net, ipgre_net_id);
414
415 ipgre_tunnel_unlink(ign, netdev_priv(dev));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 dev_put(dev);
417}
418
419
420static void ipgre_err(struct sk_buff *skb, u32 info)
421{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422
Rami Rosen071f92d2008-05-21 17:47:54 -0700423/* All the routers (except for Linux) return only
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 8 bytes of packet payload. It means, that precise relaying of
425 ICMP in the real Internet is absolutely infeasible.
426
427 Moreover, Cisco "wise men" put GRE key to the third word
428 in GRE header. It makes impossible maintaining even soft state for keyed
429 GRE tunnels with enabled checksum. Tell them "thank you".
430
431 Well, I wonder, rfc1812 was written by Cisco employee,
432 what the hell these idiots break standrads established
433 by themself???
434 */
435
Jianjun Kong6ed25332008-11-03 00:25:16 -0800436 struct iphdr *iph = (struct iphdr *)skb->data;
Al Virod5a0a1e2006-11-08 00:23:14 -0800437 __be16 *p = (__be16*)(skb->data+(iph->ihl<<2));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 int grehlen = (iph->ihl<<2) + 4;
Arnaldo Carvalho de Melo88c76642007-03-13 14:43:18 -0300439 const int type = icmp_hdr(skb)->type;
440 const int code = icmp_hdr(skb)->code;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 struct ip_tunnel *t;
Al Virod5a0a1e2006-11-08 00:23:14 -0800442 __be16 flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443
444 flags = p[0];
445 if (flags&(GRE_CSUM|GRE_KEY|GRE_SEQ|GRE_ROUTING|GRE_VERSION)) {
446 if (flags&(GRE_VERSION|GRE_ROUTING))
447 return;
448 if (flags&GRE_KEY) {
449 grehlen += 4;
450 if (flags&GRE_CSUM)
451 grehlen += 4;
452 }
453 }
454
455 /* If only 8 bytes returned, keyed message will be dropped here */
456 if (skb_headlen(skb) < grehlen)
457 return;
458
459 switch (type) {
460 default:
461 case ICMP_PARAMETERPROB:
462 return;
463
464 case ICMP_DEST_UNREACH:
465 switch (code) {
466 case ICMP_SR_FAILED:
467 case ICMP_PORT_UNREACH:
468 /* Impossible event. */
469 return;
470 case ICMP_FRAG_NEEDED:
471 /* Soft state for pmtu is maintained by IP core. */
472 return;
473 default:
474 /* All others are translated to HOST_UNREACH.
475 rfc2003 contains "deep thoughts" about NET_UNREACH,
476 I believe they are just ether pollution. --ANK
477 */
478 break;
479 }
480 break;
481 case ICMP_TIME_EXCEEDED:
482 if (code != ICMP_EXC_TTL)
483 return;
484 break;
485 }
486
Eric Dumazet8d5b2c02009-10-23 06:14:38 +0000487 rcu_read_lock();
Timo Teras749c10f2009-01-19 17:22:12 -0800488 t = ipgre_tunnel_lookup(skb->dev, iph->daddr, iph->saddr,
Herbert Xue1a80002008-10-09 12:00:17 -0700489 flags & GRE_KEY ?
490 *(((__be32 *)p) + (grehlen / 4) - 1) : 0,
491 p[1]);
Joe Perchesf97c1e02007-12-16 13:45:43 -0800492 if (t == NULL || t->parms.iph.daddr == 0 ||
493 ipv4_is_multicast(t->parms.iph.daddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 goto out;
495
496 if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED)
497 goto out;
498
Wei Yongjunda6185d82009-02-24 23:34:48 -0800499 if (time_before(jiffies, t->err_time + IPTUNNEL_ERR_TIMEO))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 t->err_count++;
501 else
502 t->err_count = 1;
503 t->err_time = jiffies;
504out:
Eric Dumazet8d5b2c02009-10-23 06:14:38 +0000505 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506}
507
508static inline void ipgre_ecn_decapsulate(struct iphdr *iph, struct sk_buff *skb)
509{
510 if (INET_ECN_is_ce(iph->tos)) {
511 if (skb->protocol == htons(ETH_P_IP)) {
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700512 IP_ECN_set_ce(ip_hdr(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 } else if (skb->protocol == htons(ETH_P_IPV6)) {
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700514 IP6_ECN_set_ce(ipv6_hdr(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 }
516 }
517}
518
519static inline u8
520ipgre_ecn_encapsulate(u8 tos, struct iphdr *old_iph, struct sk_buff *skb)
521{
522 u8 inner = 0;
523 if (skb->protocol == htons(ETH_P_IP))
524 inner = old_iph->tos;
525 else if (skb->protocol == htons(ETH_P_IPV6))
526 inner = ipv6_get_dsfield((struct ipv6hdr *)old_iph);
527 return INET_ECN_encapsulate(tos, inner);
528}
529
530static int ipgre_rcv(struct sk_buff *skb)
531{
532 struct iphdr *iph;
533 u8 *h;
Al Virod5a0a1e2006-11-08 00:23:14 -0800534 __be16 flags;
Al Virod3bc23e2006-11-14 21:24:49 -0800535 __sum16 csum = 0;
Al Virod5a0a1e2006-11-08 00:23:14 -0800536 __be32 key = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 u32 seqno = 0;
538 struct ip_tunnel *tunnel;
539 int offset = 4;
Herbert Xue1a80002008-10-09 12:00:17 -0700540 __be16 gre_proto;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541
542 if (!pskb_may_pull(skb, 16))
543 goto drop_nolock;
544
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700545 iph = ip_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 h = skb->data;
Al Virod5a0a1e2006-11-08 00:23:14 -0800547 flags = *(__be16*)h;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548
549 if (flags&(GRE_CSUM|GRE_KEY|GRE_ROUTING|GRE_SEQ|GRE_VERSION)) {
550 /* - Version must be 0.
551 - We do not support routing headers.
552 */
553 if (flags&(GRE_VERSION|GRE_ROUTING))
554 goto drop_nolock;
555
556 if (flags&GRE_CSUM) {
Herbert Xufb286bb2005-11-10 13:01:24 -0800557 switch (skb->ip_summed) {
Patrick McHardy84fa7932006-08-29 16:44:56 -0700558 case CHECKSUM_COMPLETE:
Al Virod3bc23e2006-11-14 21:24:49 -0800559 csum = csum_fold(skb->csum);
Herbert Xufb286bb2005-11-10 13:01:24 -0800560 if (!csum)
561 break;
562 /* fall through */
563 case CHECKSUM_NONE:
564 skb->csum = 0;
565 csum = __skb_checksum_complete(skb);
Patrick McHardy84fa7932006-08-29 16:44:56 -0700566 skb->ip_summed = CHECKSUM_COMPLETE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567 }
568 offset += 4;
569 }
570 if (flags&GRE_KEY) {
Al Virod5a0a1e2006-11-08 00:23:14 -0800571 key = *(__be32*)(h + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572 offset += 4;
573 }
574 if (flags&GRE_SEQ) {
Al Virod5a0a1e2006-11-08 00:23:14 -0800575 seqno = ntohl(*(__be32*)(h + offset));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 offset += 4;
577 }
578 }
579
Herbert Xue1a80002008-10-09 12:00:17 -0700580 gre_proto = *(__be16 *)(h + 2);
581
Eric Dumazet8d5b2c02009-10-23 06:14:38 +0000582 rcu_read_lock();
Timo Teras749c10f2009-01-19 17:22:12 -0800583 if ((tunnel = ipgre_tunnel_lookup(skb->dev,
Herbert Xue1a80002008-10-09 12:00:17 -0700584 iph->saddr, iph->daddr, key,
585 gre_proto))) {
Pavel Emelyanovaddd68e2008-05-21 14:14:22 -0700586 struct net_device_stats *stats = &tunnel->dev->stats;
587
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588 secpath_reset(skb);
589
Herbert Xue1a80002008-10-09 12:00:17 -0700590 skb->protocol = gre_proto;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591 /* WCCP version 1 and 2 protocol decoding.
592 * - Change protocol to IP
593 * - When dealing with WCCPv2, Skip extra 4 bytes in GRE header
594 */
Herbert Xue1a80002008-10-09 12:00:17 -0700595 if (flags == 0 && gre_proto == htons(ETH_P_WCCP)) {
YOSHIFUJI Hideaki496c98d2006-10-10 19:41:21 -0700596 skb->protocol = htons(ETH_P_IP);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900597 if ((*(h + offset) & 0xF0) != 0x40)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 offset += 4;
599 }
600
Timo Teras1d069162007-12-20 00:10:33 -0800601 skb->mac_header = skb->network_header;
Arnaldo Carvalho de Melo4209fb62007-03-10 18:42:03 -0300602 __pskb_pull(skb, offset);
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -0700603 skb_postpull_rcsum(skb, skb_transport_header(skb), offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 skb->pkt_type = PACKET_HOST;
605#ifdef CONFIG_NET_IPGRE_BROADCAST
Joe Perchesf97c1e02007-12-16 13:45:43 -0800606 if (ipv4_is_multicast(iph->daddr)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 /* Looped back packet, drop it! */
Eric Dumazet511c3f92009-06-02 05:14:27 +0000608 if (skb_rtable(skb)->fl.iif == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 goto drop;
Pavel Emelyanovaddd68e2008-05-21 14:14:22 -0700610 stats->multicast++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 skb->pkt_type = PACKET_BROADCAST;
612 }
613#endif
614
615 if (((flags&GRE_CSUM) && csum) ||
616 (!(flags&GRE_CSUM) && tunnel->parms.i_flags&GRE_CSUM)) {
Pavel Emelyanovaddd68e2008-05-21 14:14:22 -0700617 stats->rx_crc_errors++;
618 stats->rx_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 goto drop;
620 }
621 if (tunnel->parms.i_flags&GRE_SEQ) {
622 if (!(flags&GRE_SEQ) ||
623 (tunnel->i_seqno && (s32)(seqno - tunnel->i_seqno) < 0)) {
Pavel Emelyanovaddd68e2008-05-21 14:14:22 -0700624 stats->rx_fifo_errors++;
625 stats->rx_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626 goto drop;
627 }
628 tunnel->i_seqno = seqno + 1;
629 }
Herbert Xue1a80002008-10-09 12:00:17 -0700630
631 /* Warning: All skb pointers will be invalidated! */
632 if (tunnel->dev->type == ARPHRD_ETHER) {
633 if (!pskb_may_pull(skb, ETH_HLEN)) {
634 stats->rx_length_errors++;
635 stats->rx_errors++;
636 goto drop;
637 }
638
639 iph = ip_hdr(skb);
640 skb->protocol = eth_type_trans(skb, tunnel->dev);
641 skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN);
642 }
643
Eric Dumazetd19d56d2010-05-17 22:36:55 -0700644 skb_tunnel_rx(skb, tunnel->dev);
Herbert Xue1a80002008-10-09 12:00:17 -0700645
646 skb_reset_network_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647 ipgre_ecn_decapsulate(iph, skb);
Herbert Xue1a80002008-10-09 12:00:17 -0700648
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 netif_rx(skb);
Eric Dumazet8d5b2c02009-10-23 06:14:38 +0000650 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 return(0);
652 }
Herbert Xu45af08b2006-04-05 22:31:19 -0700653 icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654
655drop:
Eric Dumazet8d5b2c02009-10-23 06:14:38 +0000656 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657drop_nolock:
658 kfree_skb(skb);
659 return(0);
660}
661
Stephen Hemminger6fef4c02009-08-31 19:50:41 +0000662static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663{
Patrick McHardy2941a482006-01-08 22:05:26 -0800664 struct ip_tunnel *tunnel = netdev_priv(dev);
Eric Dumazet0bfbedb2009-10-05 00:11:22 -0700665 struct net_device_stats *stats = &dev->stats;
666 struct netdev_queue *txq = netdev_get_tx_queue(dev, 0);
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700667 struct iphdr *old_iph = ip_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 struct iphdr *tiph;
669 u8 tos;
Al Virod5a0a1e2006-11-08 00:23:14 -0800670 __be16 df;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 struct rtable *rt; /* Route to the other host */
672 struct net_device *tdev; /* Device to other host */
673 struct iphdr *iph; /* Our new IP header */
Chuck Leverc2636b42007-10-23 21:07:32 -0700674 unsigned int max_headroom; /* The extra header space needed */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 int gre_hlen;
Al Virod5a0a1e2006-11-08 00:23:14 -0800676 __be32 dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 int mtu;
678
Herbert Xue1a80002008-10-09 12:00:17 -0700679 if (dev->type == ARPHRD_ETHER)
680 IPCB(skb)->flags = 0;
681
682 if (dev->header_ops && dev->type == ARPHRD_IPGRE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 gre_hlen = 0;
Jianjun Kong6ed25332008-11-03 00:25:16 -0800684 tiph = (struct iphdr *)skb->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 } else {
686 gre_hlen = tunnel->hlen;
687 tiph = &tunnel->parms.iph;
688 }
689
690 if ((dst = tiph->daddr) == 0) {
691 /* NBMA tunnel */
692
Eric Dumazetadf30902009-06-02 05:19:30 +0000693 if (skb_dst(skb) == NULL) {
Pavel Emelyanovaddd68e2008-05-21 14:14:22 -0700694 stats->tx_fifo_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 goto tx_error;
696 }
697
698 if (skb->protocol == htons(ETH_P_IP)) {
Eric Dumazet511c3f92009-06-02 05:14:27 +0000699 rt = skb_rtable(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 if ((dst = rt->rt_gateway) == 0)
701 goto tx_error_icmp;
702 }
703#ifdef CONFIG_IPV6
704 else if (skb->protocol == htons(ETH_P_IPV6)) {
705 struct in6_addr *addr6;
706 int addr_type;
Eric Dumazetadf30902009-06-02 05:19:30 +0000707 struct neighbour *neigh = skb_dst(skb)->neighbour;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708
709 if (neigh == NULL)
710 goto tx_error;
711
Jianjun Kong6ed25332008-11-03 00:25:16 -0800712 addr6 = (struct in6_addr *)&neigh->primary_key;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 addr_type = ipv6_addr_type(addr6);
714
715 if (addr_type == IPV6_ADDR_ANY) {
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700716 addr6 = &ipv6_hdr(skb)->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 addr_type = ipv6_addr_type(addr6);
718 }
719
720 if ((addr_type & IPV6_ADDR_COMPATv4) == 0)
721 goto tx_error_icmp;
722
723 dst = addr6->s6_addr32[3];
724 }
725#endif
726 else
727 goto tx_error;
728 }
729
730 tos = tiph->tos;
Andreas Jaggiee686ca2009-07-14 09:35:59 -0700731 if (tos == 1) {
732 tos = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 if (skb->protocol == htons(ETH_P_IP))
734 tos = old_iph->tos;
Stephen Hemmingerdd4ba832010-07-08 21:35:58 -0700735 else if (skb->protocol == htons(ETH_P_IPV6))
736 tos = ipv6_get_dsfield((struct ipv6hdr *)old_iph);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 }
738
739 {
740 struct flowi fl = { .oif = tunnel->parms.link,
741 .nl_u = { .ip4_u =
742 { .daddr = dst,
743 .saddr = tiph->saddr,
744 .tos = RT_TOS(tos) } },
745 .proto = IPPROTO_GRE };
Pavel Emelyanov96635522008-04-16 01:10:44 -0700746 if (ip_route_output_key(dev_net(dev), &rt, &fl)) {
Pavel Emelyanovaddd68e2008-05-21 14:14:22 -0700747 stats->tx_carrier_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 goto tx_error;
749 }
750 }
Changli Gaod8d1f302010-06-10 23:31:35 -0700751 tdev = rt->dst.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752
753 if (tdev == dev) {
754 ip_rt_put(rt);
Pavel Emelyanovaddd68e2008-05-21 14:14:22 -0700755 stats->collisions++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 goto tx_error;
757 }
758
759 df = tiph->frag_off;
760 if (df)
Changli Gaod8d1f302010-06-10 23:31:35 -0700761 mtu = dst_mtu(&rt->dst) - dev->hard_header_len - tunnel->hlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 else
Eric Dumazetadf30902009-06-02 05:19:30 +0000763 mtu = skb_dst(skb) ? dst_mtu(skb_dst(skb)) : dev->mtu;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764
Eric Dumazetadf30902009-06-02 05:19:30 +0000765 if (skb_dst(skb))
766 skb_dst(skb)->ops->update_pmtu(skb_dst(skb), mtu);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767
768 if (skb->protocol == htons(ETH_P_IP)) {
769 df |= (old_iph->frag_off&htons(IP_DF));
770
771 if ((old_iph->frag_off&htons(IP_DF)) &&
772 mtu < ntohs(old_iph->tot_len)) {
773 icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));
774 ip_rt_put(rt);
775 goto tx_error;
776 }
777 }
778#ifdef CONFIG_IPV6
779 else if (skb->protocol == htons(ETH_P_IPV6)) {
Eric Dumazetadf30902009-06-02 05:19:30 +0000780 struct rt6_info *rt6 = (struct rt6_info *)skb_dst(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781
Eric Dumazetadf30902009-06-02 05:19:30 +0000782 if (rt6 && mtu < dst_mtu(skb_dst(skb)) && mtu >= IPV6_MIN_MTU) {
Joe Perchesf97c1e02007-12-16 13:45:43 -0800783 if ((tunnel->parms.iph.daddr &&
784 !ipv4_is_multicast(tunnel->parms.iph.daddr)) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 rt6->rt6i_dst.plen == 128) {
786 rt6->rt6i_flags |= RTF_MODIFIED;
Eric Dumazetadf30902009-06-02 05:19:30 +0000787 skb_dst(skb)->metrics[RTAX_MTU-1] = mtu;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 }
789 }
790
791 if (mtu >= IPV6_MIN_MTU && mtu < skb->len - tunnel->hlen + gre_hlen) {
Alexey Dobriyan3ffe5332010-02-18 08:25:24 +0000792 icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 ip_rt_put(rt);
794 goto tx_error;
795 }
796 }
797#endif
798
799 if (tunnel->err_count > 0) {
Wei Yongjunda6185d82009-02-24 23:34:48 -0800800 if (time_before(jiffies,
801 tunnel->err_time + IPTUNNEL_ERR_TIMEO)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802 tunnel->err_count--;
803
804 dst_link_failure(skb);
805 } else
806 tunnel->err_count = 0;
807 }
808
Changli Gaod8d1f302010-06-10 23:31:35 -0700809 max_headroom = LL_RESERVED_SPACE(tdev) + gre_hlen + rt->dst.header_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810
Patrick McHardycfbba492007-07-09 15:33:40 -0700811 if (skb_headroom(skb) < max_headroom || skb_shared(skb)||
812 (skb_cloned(skb) && !skb_clone_writable(skb, 0))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom);
Timo Teräs243aad82010-03-20 02:27:58 +0000814 if (max_headroom > dev->needed_headroom)
815 dev->needed_headroom = max_headroom;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 if (!new_skb) {
817 ip_rt_put(rt);
Eric Dumazet0bfbedb2009-10-05 00:11:22 -0700818 txq->tx_dropped++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819 dev_kfree_skb(skb);
Patrick McHardy6ed10652009-06-23 06:03:08 +0000820 return NETDEV_TX_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 }
822 if (skb->sk)
823 skb_set_owner_w(new_skb, skb->sk);
824 dev_kfree_skb(skb);
825 skb = new_skb;
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700826 old_iph = ip_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 }
828
Herbert Xu64194c32008-10-09 12:03:17 -0700829 skb_reset_transport_header(skb);
Arnaldo Carvalho de Meloe2d1bca2007-04-10 20:46:21 -0700830 skb_push(skb, gre_hlen);
831 skb_reset_network_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
Patrick McHardy48d5cad2006-02-15 15:10:22 -0800833 IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED |
834 IPSKB_REROUTED);
Eric Dumazetadf30902009-06-02 05:19:30 +0000835 skb_dst_drop(skb);
Changli Gaod8d1f302010-06-10 23:31:35 -0700836 skb_dst_set(skb, &rt->dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837
838 /*
839 * Push down and install the IPIP header.
840 */
841
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700842 iph = ip_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 iph->version = 4;
844 iph->ihl = sizeof(struct iphdr) >> 2;
845 iph->frag_off = df;
846 iph->protocol = IPPROTO_GRE;
847 iph->tos = ipgre_ecn_encapsulate(tos, old_iph, skb);
848 iph->daddr = rt->rt_dst;
849 iph->saddr = rt->rt_src;
850
851 if ((iph->ttl = tiph->ttl) == 0) {
852 if (skb->protocol == htons(ETH_P_IP))
853 iph->ttl = old_iph->ttl;
854#ifdef CONFIG_IPV6
855 else if (skb->protocol == htons(ETH_P_IPV6))
Jianjun Kong6ed25332008-11-03 00:25:16 -0800856 iph->ttl = ((struct ipv6hdr *)old_iph)->hop_limit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857#endif
858 else
Changli Gaod8d1f302010-06-10 23:31:35 -0700859 iph->ttl = dst_metric(&rt->dst, RTAX_HOPLIMIT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 }
861
Herbert Xue1a80002008-10-09 12:00:17 -0700862 ((__be16 *)(iph + 1))[0] = tunnel->parms.o_flags;
863 ((__be16 *)(iph + 1))[1] = (dev->type == ARPHRD_ETHER) ?
864 htons(ETH_P_TEB) : skb->protocol;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865
866 if (tunnel->parms.o_flags&(GRE_KEY|GRE_CSUM|GRE_SEQ)) {
Al Virod5a0a1e2006-11-08 00:23:14 -0800867 __be32 *ptr = (__be32*)(((u8*)iph) + tunnel->hlen - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868
869 if (tunnel->parms.o_flags&GRE_SEQ) {
870 ++tunnel->o_seqno;
871 *ptr = htonl(tunnel->o_seqno);
872 ptr--;
873 }
874 if (tunnel->parms.o_flags&GRE_KEY) {
875 *ptr = tunnel->parms.o_key;
876 ptr--;
877 }
878 if (tunnel->parms.o_flags&GRE_CSUM) {
879 *ptr = 0;
Al Viro5f92a732006-11-14 21:36:54 -0800880 *(__sum16*)ptr = ip_compute_csum((void*)(iph+1), skb->len - sizeof(struct iphdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 }
882 }
883
884 nf_reset(skb);
885
886 IPTUNNEL_XMIT();
Patrick McHardy6ed10652009-06-23 06:03:08 +0000887 return NETDEV_TX_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888
889tx_error_icmp:
890 dst_link_failure(skb);
891
892tx_error:
893 stats->tx_errors++;
894 dev_kfree_skb(skb);
Patrick McHardy6ed10652009-06-23 06:03:08 +0000895 return NETDEV_TX_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896}
897
Herbert Xu42aa9162008-10-09 11:59:32 -0700898static int ipgre_tunnel_bind_dev(struct net_device *dev)
Michal Schmidtee34c1e2007-12-13 09:46:32 -0800899{
900 struct net_device *tdev = NULL;
901 struct ip_tunnel *tunnel;
902 struct iphdr *iph;
903 int hlen = LL_MAX_HEADER;
904 int mtu = ETH_DATA_LEN;
905 int addend = sizeof(struct iphdr) + 4;
906
907 tunnel = netdev_priv(dev);
908 iph = &tunnel->parms.iph;
909
Herbert Xuc95b8192008-10-09 11:58:54 -0700910 /* Guess output device to choose reasonable mtu and needed_headroom */
Michal Schmidtee34c1e2007-12-13 09:46:32 -0800911
912 if (iph->daddr) {
913 struct flowi fl = { .oif = tunnel->parms.link,
914 .nl_u = { .ip4_u =
915 { .daddr = iph->daddr,
916 .saddr = iph->saddr,
917 .tos = RT_TOS(iph->tos) } },
918 .proto = IPPROTO_GRE };
919 struct rtable *rt;
Pavel Emelyanov96635522008-04-16 01:10:44 -0700920 if (!ip_route_output_key(dev_net(dev), &rt, &fl)) {
Changli Gaod8d1f302010-06-10 23:31:35 -0700921 tdev = rt->dst.dev;
Michal Schmidtee34c1e2007-12-13 09:46:32 -0800922 ip_rt_put(rt);
923 }
Herbert Xue1a80002008-10-09 12:00:17 -0700924
925 if (dev->type != ARPHRD_ETHER)
926 dev->flags |= IFF_POINTOPOINT;
Michal Schmidtee34c1e2007-12-13 09:46:32 -0800927 }
928
929 if (!tdev && tunnel->parms.link)
Pavel Emelyanov96635522008-04-16 01:10:44 -0700930 tdev = __dev_get_by_index(dev_net(dev), tunnel->parms.link);
Michal Schmidtee34c1e2007-12-13 09:46:32 -0800931
932 if (tdev) {
Herbert Xuc95b8192008-10-09 11:58:54 -0700933 hlen = tdev->hard_header_len + tdev->needed_headroom;
Michal Schmidtee34c1e2007-12-13 09:46:32 -0800934 mtu = tdev->mtu;
935 }
936 dev->iflink = tunnel->parms.link;
937
938 /* Precalculate GRE options length */
939 if (tunnel->parms.o_flags&(GRE_CSUM|GRE_KEY|GRE_SEQ)) {
940 if (tunnel->parms.o_flags&GRE_CSUM)
941 addend += 4;
942 if (tunnel->parms.o_flags&GRE_KEY)
943 addend += 4;
944 if (tunnel->parms.o_flags&GRE_SEQ)
945 addend += 4;
946 }
Herbert Xuc95b8192008-10-09 11:58:54 -0700947 dev->needed_headroom = addend + hlen;
Tom Goff8cdb0452009-08-14 16:33:56 -0700948 mtu -= dev->hard_header_len + addend;
Herbert Xu42aa9162008-10-09 11:59:32 -0700949
950 if (mtu < 68)
951 mtu = 68;
952
Michal Schmidtee34c1e2007-12-13 09:46:32 -0800953 tunnel->hlen = addend;
954
Herbert Xu42aa9162008-10-09 11:59:32 -0700955 return mtu;
Michal Schmidtee34c1e2007-12-13 09:46:32 -0800956}
957
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958static int
959ipgre_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
960{
961 int err = 0;
962 struct ip_tunnel_parm p;
963 struct ip_tunnel *t;
Pavel Emelyanovf57e7d52008-04-16 01:09:22 -0700964 struct net *net = dev_net(dev);
965 struct ipgre_net *ign = net_generic(net, ipgre_net_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966
967 switch (cmd) {
968 case SIOCGETTUNNEL:
969 t = NULL;
Pavel Emelyanov7daa0002008-04-16 01:10:05 -0700970 if (dev == ign->fb_tunnel_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971 if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) {
972 err = -EFAULT;
973 break;
974 }
Pavel Emelyanovf57e7d52008-04-16 01:09:22 -0700975 t = ipgre_tunnel_locate(net, &p, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 }
977 if (t == NULL)
Patrick McHardy2941a482006-01-08 22:05:26 -0800978 t = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 memcpy(&p, &t->parms, sizeof(p));
980 if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p)))
981 err = -EFAULT;
982 break;
983
984 case SIOCADDTUNNEL:
985 case SIOCCHGTUNNEL:
986 err = -EPERM;
987 if (!capable(CAP_NET_ADMIN))
988 goto done;
989
990 err = -EFAULT;
991 if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
992 goto done;
993
994 err = -EINVAL;
995 if (p.iph.version != 4 || p.iph.protocol != IPPROTO_GRE ||
996 p.iph.ihl != 5 || (p.iph.frag_off&htons(~IP_DF)) ||
997 ((p.i_flags|p.o_flags)&(GRE_VERSION|GRE_ROUTING)))
998 goto done;
999 if (p.iph.ttl)
1000 p.iph.frag_off |= htons(IP_DF);
1001
1002 if (!(p.i_flags&GRE_KEY))
1003 p.i_key = 0;
1004 if (!(p.o_flags&GRE_KEY))
1005 p.o_key = 0;
1006
Pavel Emelyanovf57e7d52008-04-16 01:09:22 -07001007 t = ipgre_tunnel_locate(net, &p, cmd == SIOCADDTUNNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008
Pavel Emelyanov7daa0002008-04-16 01:10:05 -07001009 if (dev != ign->fb_tunnel_dev && cmd == SIOCCHGTUNNEL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 if (t != NULL) {
1011 if (t->dev != dev) {
1012 err = -EEXIST;
1013 break;
1014 }
1015 } else {
Jianjun Kong6ed25332008-11-03 00:25:16 -08001016 unsigned nflags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017
Patrick McHardy2941a482006-01-08 22:05:26 -08001018 t = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019
Joe Perchesf97c1e02007-12-16 13:45:43 -08001020 if (ipv4_is_multicast(p.iph.daddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 nflags = IFF_BROADCAST;
1022 else if (p.iph.daddr)
1023 nflags = IFF_POINTOPOINT;
1024
1025 if ((dev->flags^nflags)&(IFF_POINTOPOINT|IFF_BROADCAST)) {
1026 err = -EINVAL;
1027 break;
1028 }
Pavel Emelyanovf57e7d52008-04-16 01:09:22 -07001029 ipgre_tunnel_unlink(ign, t);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030 t->parms.iph.saddr = p.iph.saddr;
1031 t->parms.iph.daddr = p.iph.daddr;
1032 t->parms.i_key = p.i_key;
1033 t->parms.o_key = p.o_key;
1034 memcpy(dev->dev_addr, &p.iph.saddr, 4);
1035 memcpy(dev->broadcast, &p.iph.daddr, 4);
Pavel Emelyanovf57e7d52008-04-16 01:09:22 -07001036 ipgre_tunnel_link(ign, t);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037 netdev_state_change(dev);
1038 }
1039 }
1040
1041 if (t) {
1042 err = 0;
1043 if (cmd == SIOCCHGTUNNEL) {
1044 t->parms.iph.ttl = p.iph.ttl;
1045 t->parms.iph.tos = p.iph.tos;
1046 t->parms.iph.frag_off = p.iph.frag_off;
Michal Schmidtee34c1e2007-12-13 09:46:32 -08001047 if (t->parms.link != p.link) {
1048 t->parms.link = p.link;
Herbert Xu42aa9162008-10-09 11:59:32 -07001049 dev->mtu = ipgre_tunnel_bind_dev(dev);
Michal Schmidtee34c1e2007-12-13 09:46:32 -08001050 netdev_state_change(dev);
1051 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052 }
1053 if (copy_to_user(ifr->ifr_ifru.ifru_data, &t->parms, sizeof(p)))
1054 err = -EFAULT;
1055 } else
1056 err = (cmd == SIOCADDTUNNEL ? -ENOBUFS : -ENOENT);
1057 break;
1058
1059 case SIOCDELTUNNEL:
1060 err = -EPERM;
1061 if (!capable(CAP_NET_ADMIN))
1062 goto done;
1063
Pavel Emelyanov7daa0002008-04-16 01:10:05 -07001064 if (dev == ign->fb_tunnel_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065 err = -EFAULT;
1066 if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
1067 goto done;
1068 err = -ENOENT;
Pavel Emelyanovf57e7d52008-04-16 01:09:22 -07001069 if ((t = ipgre_tunnel_locate(net, &p, 0)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 goto done;
1071 err = -EPERM;
Pavel Emelyanov7daa0002008-04-16 01:10:05 -07001072 if (t == netdev_priv(ign->fb_tunnel_dev))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073 goto done;
1074 dev = t->dev;
1075 }
Stephen Hemminger22f8cde2007-02-07 00:09:58 -08001076 unregister_netdevice(dev);
1077 err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078 break;
1079
1080 default:
1081 err = -EINVAL;
1082 }
1083
1084done:
1085 return err;
1086}
1087
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088static int ipgre_tunnel_change_mtu(struct net_device *dev, int new_mtu)
1089{
Patrick McHardy2941a482006-01-08 22:05:26 -08001090 struct ip_tunnel *tunnel = netdev_priv(dev);
Herbert Xuc95b8192008-10-09 11:58:54 -07001091 if (new_mtu < 68 ||
1092 new_mtu > 0xFFF8 - dev->hard_header_len - tunnel->hlen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093 return -EINVAL;
1094 dev->mtu = new_mtu;
1095 return 0;
1096}
1097
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098/* Nice toy. Unfortunately, useless in real life :-)
1099 It allows to construct virtual multiprotocol broadcast "LAN"
1100 over the Internet, provided multicast routing is tuned.
1101
1102
1103 I have no idea was this bicycle invented before me,
1104 so that I had to set ARPHRD_IPGRE to a random value.
1105 I have an impression, that Cisco could make something similar,
1106 but this feature is apparently missing in IOS<=11.2(8).
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001107
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108 I set up 10.66.66/24 and fec0:6666:6666::0/96 as virtual networks
1109 with broadcast 224.66.66.66. If you have access to mbone, play with me :-)
1110
1111 ping -t 255 224.66.66.66
1112
1113 If nobody answers, mbone does not work.
1114
1115 ip tunnel add Universe mode gre remote 224.66.66.66 local <Your_real_addr> ttl 255
1116 ip addr add 10.66.66.<somewhat>/24 dev Universe
1117 ifconfig Universe up
1118 ifconfig Universe add fe80::<Your_real_addr>/10
1119 ifconfig Universe add fec0:6666:6666::<Your_real_addr>/96
1120 ftp 10.66.66.66
1121 ...
1122 ftp fec0:6666:6666::193.233.7.65
1123 ...
1124
1125 */
1126
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -07001127static int ipgre_header(struct sk_buff *skb, struct net_device *dev,
1128 unsigned short type,
1129 const void *daddr, const void *saddr, unsigned len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130{
Patrick McHardy2941a482006-01-08 22:05:26 -08001131 struct ip_tunnel *t = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132 struct iphdr *iph = (struct iphdr *)skb_push(skb, t->hlen);
Al Virod5a0a1e2006-11-08 00:23:14 -08001133 __be16 *p = (__be16*)(iph+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134
1135 memcpy(iph, &t->parms.iph, sizeof(struct iphdr));
1136 p[0] = t->parms.o_flags;
1137 p[1] = htons(type);
1138
1139 /*
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001140 * Set the source hardware address.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141 */
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001142
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143 if (saddr)
1144 memcpy(&iph->saddr, saddr, 4);
Timo Teräs6d55cb92010-03-03 04:01:13 +00001145 if (daddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146 memcpy(&iph->daddr, daddr, 4);
Timo Teräs6d55cb92010-03-03 04:01:13 +00001147 if (iph->daddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148 return t->hlen;
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001149
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150 return -t->hlen;
1151}
1152
Timo Teras6a5f44d2007-10-23 20:31:53 -07001153static int ipgre_header_parse(const struct sk_buff *skb, unsigned char *haddr)
1154{
Jianjun Kong6ed25332008-11-03 00:25:16 -08001155 struct iphdr *iph = (struct iphdr *) skb_mac_header(skb);
Timo Teras6a5f44d2007-10-23 20:31:53 -07001156 memcpy(haddr, &iph->saddr, 4);
1157 return 4;
1158}
1159
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -07001160static const struct header_ops ipgre_header_ops = {
1161 .create = ipgre_header,
Timo Teras6a5f44d2007-10-23 20:31:53 -07001162 .parse = ipgre_header_parse,
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -07001163};
1164
Timo Teras6a5f44d2007-10-23 20:31:53 -07001165#ifdef CONFIG_NET_IPGRE_BROADCAST
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166static int ipgre_open(struct net_device *dev)
1167{
Patrick McHardy2941a482006-01-08 22:05:26 -08001168 struct ip_tunnel *t = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169
Joe Perchesf97c1e02007-12-16 13:45:43 -08001170 if (ipv4_is_multicast(t->parms.iph.daddr)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171 struct flowi fl = { .oif = t->parms.link,
1172 .nl_u = { .ip4_u =
1173 { .daddr = t->parms.iph.daddr,
1174 .saddr = t->parms.iph.saddr,
1175 .tos = RT_TOS(t->parms.iph.tos) } },
1176 .proto = IPPROTO_GRE };
1177 struct rtable *rt;
Pavel Emelyanov96635522008-04-16 01:10:44 -07001178 if (ip_route_output_key(dev_net(dev), &rt, &fl))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179 return -EADDRNOTAVAIL;
Changli Gaod8d1f302010-06-10 23:31:35 -07001180 dev = rt->dst.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181 ip_rt_put(rt);
Herbert Xue5ed6392005-10-03 14:35:55 -07001182 if (__in_dev_get_rtnl(dev) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183 return -EADDRNOTAVAIL;
1184 t->mlink = dev->ifindex;
Herbert Xue5ed6392005-10-03 14:35:55 -07001185 ip_mc_inc_group(__in_dev_get_rtnl(dev), t->parms.iph.daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186 }
1187 return 0;
1188}
1189
1190static int ipgre_close(struct net_device *dev)
1191{
Patrick McHardy2941a482006-01-08 22:05:26 -08001192 struct ip_tunnel *t = netdev_priv(dev);
Stephen Hemmingerb8c26a32008-11-20 20:34:29 -08001193
Joe Perchesf97c1e02007-12-16 13:45:43 -08001194 if (ipv4_is_multicast(t->parms.iph.daddr) && t->mlink) {
Denis V. Lunev7fee0ca2008-01-21 17:32:38 -08001195 struct in_device *in_dev;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001196 in_dev = inetdev_by_index(dev_net(dev), t->mlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197 if (in_dev) {
1198 ip_mc_dec_group(in_dev, t->parms.iph.daddr);
1199 in_dev_put(in_dev);
1200 }
1201 }
1202 return 0;
1203}
1204
1205#endif
1206
Stephen Hemmingerb8c26a32008-11-20 20:34:29 -08001207static const struct net_device_ops ipgre_netdev_ops = {
1208 .ndo_init = ipgre_tunnel_init,
1209 .ndo_uninit = ipgre_tunnel_uninit,
1210#ifdef CONFIG_NET_IPGRE_BROADCAST
1211 .ndo_open = ipgre_open,
1212 .ndo_stop = ipgre_close,
1213#endif
1214 .ndo_start_xmit = ipgre_tunnel_xmit,
1215 .ndo_do_ioctl = ipgre_tunnel_ioctl,
1216 .ndo_change_mtu = ipgre_tunnel_change_mtu,
1217};
1218
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219static void ipgre_tunnel_setup(struct net_device *dev)
1220{
Stephen Hemmingerb8c26a32008-11-20 20:34:29 -08001221 dev->netdev_ops = &ipgre_netdev_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222 dev->destructor = free_netdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223
1224 dev->type = ARPHRD_IPGRE;
Herbert Xuc95b8192008-10-09 11:58:54 -07001225 dev->needed_headroom = LL_MAX_HEADER + sizeof(struct iphdr) + 4;
Kris Katterjohn46f25df2006-01-05 16:35:42 -08001226 dev->mtu = ETH_DATA_LEN - sizeof(struct iphdr) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227 dev->flags = IFF_NOARP;
1228 dev->iflink = 0;
1229 dev->addr_len = 4;
Pavel Emelyanov0b67ece2008-04-16 01:11:13 -07001230 dev->features |= NETIF_F_NETNS_LOCAL;
Eric Dumazet108bfa82009-05-28 22:35:10 +00001231 dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232}
1233
1234static int ipgre_tunnel_init(struct net_device *dev)
1235{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236 struct ip_tunnel *tunnel;
1237 struct iphdr *iph;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238
Patrick McHardy2941a482006-01-08 22:05:26 -08001239 tunnel = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240 iph = &tunnel->parms.iph;
1241
1242 tunnel->dev = dev;
1243 strcpy(tunnel->parms.name, dev->name);
1244
1245 memcpy(dev->dev_addr, &tunnel->parms.iph.saddr, 4);
1246 memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4);
1247
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248 if (iph->daddr) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249#ifdef CONFIG_NET_IPGRE_BROADCAST
Joe Perchesf97c1e02007-12-16 13:45:43 -08001250 if (ipv4_is_multicast(iph->daddr)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251 if (!iph->saddr)
1252 return -EINVAL;
1253 dev->flags = IFF_BROADCAST;
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -07001254 dev->header_ops = &ipgre_header_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255 }
1256#endif
Michal Schmidtee34c1e2007-12-13 09:46:32 -08001257 } else
Timo Teras6a5f44d2007-10-23 20:31:53 -07001258 dev->header_ops = &ipgre_header_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260 return 0;
1261}
1262
Stephen Hemmingerb8c26a32008-11-20 20:34:29 -08001263static void ipgre_fb_tunnel_init(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264{
Patrick McHardy2941a482006-01-08 22:05:26 -08001265 struct ip_tunnel *tunnel = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266 struct iphdr *iph = &tunnel->parms.iph;
Pavel Emelyanoveb8ce742008-04-16 01:10:26 -07001267 struct ipgre_net *ign = net_generic(dev_net(dev), ipgre_net_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268
1269 tunnel->dev = dev;
1270 strcpy(tunnel->parms.name, dev->name);
1271
1272 iph->version = 4;
1273 iph->protocol = IPPROTO_GRE;
1274 iph->ihl = 5;
1275 tunnel->hlen = sizeof(struct iphdr) + 4;
1276
1277 dev_hold(dev);
Pavel Emelyanoveb8ce742008-04-16 01:10:26 -07001278 ign->tunnels_wc[0] = tunnel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279}
1280
1281
Dmitry Kozlov00959ad2010-08-21 23:05:39 -07001282static const struct gre_protocol ipgre_protocol = {
1283 .handler = ipgre_rcv,
1284 .err_handler = ipgre_err,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285};
1286
Eric Dumazeteef6dd62009-10-27 07:07:16 +00001287static void ipgre_destroy_tunnels(struct ipgre_net *ign, struct list_head *head)
Pavel Emelyanoveb8ce742008-04-16 01:10:26 -07001288{
1289 int prio;
1290
1291 for (prio = 0; prio < 4; prio++) {
1292 int h;
1293 for (h = 0; h < HASH_SIZE; h++) {
Eric Dumazeteef6dd62009-10-27 07:07:16 +00001294 struct ip_tunnel *t = ign->tunnels[prio][h];
1295
1296 while (t != NULL) {
1297 unregister_netdevice_queue(t->dev, head);
1298 t = t->next;
1299 }
Pavel Emelyanoveb8ce742008-04-16 01:10:26 -07001300 }
1301 }
1302}
1303
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00001304static int __net_init ipgre_init_net(struct net *net)
Pavel Emelyanov59a4c752008-04-16 01:08:53 -07001305{
Eric W. Biedermancfb8fbf2009-11-29 15:46:13 +00001306 struct ipgre_net *ign = net_generic(net, ipgre_net_id);
Pavel Emelyanov59a4c752008-04-16 01:08:53 -07001307 int err;
Pavel Emelyanov59a4c752008-04-16 01:08:53 -07001308
Pavel Emelyanov7daa0002008-04-16 01:10:05 -07001309 ign->fb_tunnel_dev = alloc_netdev(sizeof(struct ip_tunnel), "gre0",
1310 ipgre_tunnel_setup);
1311 if (!ign->fb_tunnel_dev) {
1312 err = -ENOMEM;
1313 goto err_alloc_dev;
1314 }
Alexey Dobriyanbe77e592008-11-23 17:26:26 -08001315 dev_net_set(ign->fb_tunnel_dev, net);
Pavel Emelyanov7daa0002008-04-16 01:10:05 -07001316
Stephen Hemmingerb8c26a32008-11-20 20:34:29 -08001317 ipgre_fb_tunnel_init(ign->fb_tunnel_dev);
Herbert Xuc19e6542008-10-09 11:59:55 -07001318 ign->fb_tunnel_dev->rtnl_link_ops = &ipgre_link_ops;
Pavel Emelyanov7daa0002008-04-16 01:10:05 -07001319
1320 if ((err = register_netdev(ign->fb_tunnel_dev)))
1321 goto err_reg_dev;
1322
Pavel Emelyanov59a4c752008-04-16 01:08:53 -07001323 return 0;
1324
Pavel Emelyanov7daa0002008-04-16 01:10:05 -07001325err_reg_dev:
1326 free_netdev(ign->fb_tunnel_dev);
1327err_alloc_dev:
Pavel Emelyanov59a4c752008-04-16 01:08:53 -07001328 return err;
1329}
1330
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00001331static void __net_exit ipgre_exit_net(struct net *net)
Pavel Emelyanov59a4c752008-04-16 01:08:53 -07001332{
1333 struct ipgre_net *ign;
Eric Dumazeteef6dd62009-10-27 07:07:16 +00001334 LIST_HEAD(list);
Pavel Emelyanov59a4c752008-04-16 01:08:53 -07001335
1336 ign = net_generic(net, ipgre_net_id);
Pavel Emelyanov7daa0002008-04-16 01:10:05 -07001337 rtnl_lock();
Eric Dumazeteef6dd62009-10-27 07:07:16 +00001338 ipgre_destroy_tunnels(ign, &list);
1339 unregister_netdevice_many(&list);
Pavel Emelyanov7daa0002008-04-16 01:10:05 -07001340 rtnl_unlock();
Pavel Emelyanov59a4c752008-04-16 01:08:53 -07001341}
1342
1343static struct pernet_operations ipgre_net_ops = {
1344 .init = ipgre_init_net,
1345 .exit = ipgre_exit_net,
Eric W. Biedermancfb8fbf2009-11-29 15:46:13 +00001346 .id = &ipgre_net_id,
1347 .size = sizeof(struct ipgre_net),
Pavel Emelyanov59a4c752008-04-16 01:08:53 -07001348};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349
Herbert Xuc19e6542008-10-09 11:59:55 -07001350static int ipgre_tunnel_validate(struct nlattr *tb[], struct nlattr *data[])
1351{
1352 __be16 flags;
1353
1354 if (!data)
1355 return 0;
1356
1357 flags = 0;
1358 if (data[IFLA_GRE_IFLAGS])
1359 flags |= nla_get_be16(data[IFLA_GRE_IFLAGS]);
1360 if (data[IFLA_GRE_OFLAGS])
1361 flags |= nla_get_be16(data[IFLA_GRE_OFLAGS]);
1362 if (flags & (GRE_VERSION|GRE_ROUTING))
1363 return -EINVAL;
1364
1365 return 0;
1366}
1367
Herbert Xue1a80002008-10-09 12:00:17 -07001368static int ipgre_tap_validate(struct nlattr *tb[], struct nlattr *data[])
1369{
1370 __be32 daddr;
1371
1372 if (tb[IFLA_ADDRESS]) {
1373 if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN)
1374 return -EINVAL;
1375 if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS])))
1376 return -EADDRNOTAVAIL;
1377 }
1378
1379 if (!data)
1380 goto out;
1381
1382 if (data[IFLA_GRE_REMOTE]) {
1383 memcpy(&daddr, nla_data(data[IFLA_GRE_REMOTE]), 4);
1384 if (!daddr)
1385 return -EINVAL;
1386 }
1387
1388out:
1389 return ipgre_tunnel_validate(tb, data);
1390}
1391
Herbert Xuc19e6542008-10-09 11:59:55 -07001392static void ipgre_netlink_parms(struct nlattr *data[],
1393 struct ip_tunnel_parm *parms)
1394{
Herbert Xu7bb82d92008-10-11 12:20:15 -07001395 memset(parms, 0, sizeof(*parms));
Herbert Xuc19e6542008-10-09 11:59:55 -07001396
1397 parms->iph.protocol = IPPROTO_GRE;
1398
1399 if (!data)
1400 return;
1401
1402 if (data[IFLA_GRE_LINK])
1403 parms->link = nla_get_u32(data[IFLA_GRE_LINK]);
1404
1405 if (data[IFLA_GRE_IFLAGS])
1406 parms->i_flags = nla_get_be16(data[IFLA_GRE_IFLAGS]);
1407
1408 if (data[IFLA_GRE_OFLAGS])
1409 parms->o_flags = nla_get_be16(data[IFLA_GRE_OFLAGS]);
1410
1411 if (data[IFLA_GRE_IKEY])
1412 parms->i_key = nla_get_be32(data[IFLA_GRE_IKEY]);
1413
1414 if (data[IFLA_GRE_OKEY])
1415 parms->o_key = nla_get_be32(data[IFLA_GRE_OKEY]);
1416
1417 if (data[IFLA_GRE_LOCAL])
Patrick McHardy4d74f8b2008-10-10 12:11:06 -07001418 parms->iph.saddr = nla_get_be32(data[IFLA_GRE_LOCAL]);
Herbert Xuc19e6542008-10-09 11:59:55 -07001419
1420 if (data[IFLA_GRE_REMOTE])
Patrick McHardy4d74f8b2008-10-10 12:11:06 -07001421 parms->iph.daddr = nla_get_be32(data[IFLA_GRE_REMOTE]);
Herbert Xuc19e6542008-10-09 11:59:55 -07001422
1423 if (data[IFLA_GRE_TTL])
1424 parms->iph.ttl = nla_get_u8(data[IFLA_GRE_TTL]);
1425
1426 if (data[IFLA_GRE_TOS])
1427 parms->iph.tos = nla_get_u8(data[IFLA_GRE_TOS]);
1428
1429 if (!data[IFLA_GRE_PMTUDISC] || nla_get_u8(data[IFLA_GRE_PMTUDISC]))
1430 parms->iph.frag_off = htons(IP_DF);
1431}
1432
Herbert Xue1a80002008-10-09 12:00:17 -07001433static int ipgre_tap_init(struct net_device *dev)
1434{
1435 struct ip_tunnel *tunnel;
1436
1437 tunnel = netdev_priv(dev);
1438
1439 tunnel->dev = dev;
1440 strcpy(tunnel->parms.name, dev->name);
1441
1442 ipgre_tunnel_bind_dev(dev);
1443
1444 return 0;
1445}
1446
Stephen Hemmingerb8c26a32008-11-20 20:34:29 -08001447static const struct net_device_ops ipgre_tap_netdev_ops = {
1448 .ndo_init = ipgre_tap_init,
1449 .ndo_uninit = ipgre_tunnel_uninit,
1450 .ndo_start_xmit = ipgre_tunnel_xmit,
1451 .ndo_set_mac_address = eth_mac_addr,
1452 .ndo_validate_addr = eth_validate_addr,
1453 .ndo_change_mtu = ipgre_tunnel_change_mtu,
1454};
1455
Herbert Xue1a80002008-10-09 12:00:17 -07001456static void ipgre_tap_setup(struct net_device *dev)
1457{
1458
1459 ether_setup(dev);
1460
Herbert Xu2e9526b2009-10-30 05:51:48 +00001461 dev->netdev_ops = &ipgre_tap_netdev_ops;
Herbert Xue1a80002008-10-09 12:00:17 -07001462 dev->destructor = free_netdev;
Herbert Xue1a80002008-10-09 12:00:17 -07001463
1464 dev->iflink = 0;
1465 dev->features |= NETIF_F_NETNS_LOCAL;
1466}
1467
Eric W. Biederman81adee42009-11-08 00:53:51 -08001468static int ipgre_newlink(struct net *src_net, struct net_device *dev, struct nlattr *tb[],
Herbert Xuc19e6542008-10-09 11:59:55 -07001469 struct nlattr *data[])
1470{
1471 struct ip_tunnel *nt;
1472 struct net *net = dev_net(dev);
1473 struct ipgre_net *ign = net_generic(net, ipgre_net_id);
1474 int mtu;
1475 int err;
1476
1477 nt = netdev_priv(dev);
1478 ipgre_netlink_parms(data, &nt->parms);
1479
Herbert Xue1a80002008-10-09 12:00:17 -07001480 if (ipgre_tunnel_find(net, &nt->parms, dev->type))
Herbert Xuc19e6542008-10-09 11:59:55 -07001481 return -EEXIST;
1482
Herbert Xue1a80002008-10-09 12:00:17 -07001483 if (dev->type == ARPHRD_ETHER && !tb[IFLA_ADDRESS])
1484 random_ether_addr(dev->dev_addr);
1485
Herbert Xuc19e6542008-10-09 11:59:55 -07001486 mtu = ipgre_tunnel_bind_dev(dev);
1487 if (!tb[IFLA_MTU])
1488 dev->mtu = mtu;
1489
1490 err = register_netdevice(dev);
1491 if (err)
1492 goto out;
1493
1494 dev_hold(dev);
1495 ipgre_tunnel_link(ign, nt);
1496
1497out:
1498 return err;
1499}
1500
1501static int ipgre_changelink(struct net_device *dev, struct nlattr *tb[],
1502 struct nlattr *data[])
1503{
1504 struct ip_tunnel *t, *nt;
1505 struct net *net = dev_net(dev);
1506 struct ipgre_net *ign = net_generic(net, ipgre_net_id);
1507 struct ip_tunnel_parm p;
1508 int mtu;
1509
1510 if (dev == ign->fb_tunnel_dev)
1511 return -EINVAL;
1512
1513 nt = netdev_priv(dev);
1514 ipgre_netlink_parms(data, &p);
1515
1516 t = ipgre_tunnel_locate(net, &p, 0);
1517
1518 if (t) {
1519 if (t->dev != dev)
1520 return -EEXIST;
1521 } else {
Herbert Xuc19e6542008-10-09 11:59:55 -07001522 t = nt;
1523
Herbert Xu2e9526b2009-10-30 05:51:48 +00001524 if (dev->type != ARPHRD_ETHER) {
1525 unsigned nflags = 0;
Herbert Xuc19e6542008-10-09 11:59:55 -07001526
Herbert Xu2e9526b2009-10-30 05:51:48 +00001527 if (ipv4_is_multicast(p.iph.daddr))
1528 nflags = IFF_BROADCAST;
1529 else if (p.iph.daddr)
1530 nflags = IFF_POINTOPOINT;
1531
1532 if ((dev->flags ^ nflags) &
1533 (IFF_POINTOPOINT | IFF_BROADCAST))
1534 return -EINVAL;
1535 }
Herbert Xuc19e6542008-10-09 11:59:55 -07001536
1537 ipgre_tunnel_unlink(ign, t);
1538 t->parms.iph.saddr = p.iph.saddr;
1539 t->parms.iph.daddr = p.iph.daddr;
1540 t->parms.i_key = p.i_key;
Herbert Xu2e9526b2009-10-30 05:51:48 +00001541 if (dev->type != ARPHRD_ETHER) {
1542 memcpy(dev->dev_addr, &p.iph.saddr, 4);
1543 memcpy(dev->broadcast, &p.iph.daddr, 4);
1544 }
Herbert Xuc19e6542008-10-09 11:59:55 -07001545 ipgre_tunnel_link(ign, t);
1546 netdev_state_change(dev);
1547 }
1548
1549 t->parms.o_key = p.o_key;
1550 t->parms.iph.ttl = p.iph.ttl;
1551 t->parms.iph.tos = p.iph.tos;
1552 t->parms.iph.frag_off = p.iph.frag_off;
1553
1554 if (t->parms.link != p.link) {
1555 t->parms.link = p.link;
1556 mtu = ipgre_tunnel_bind_dev(dev);
1557 if (!tb[IFLA_MTU])
1558 dev->mtu = mtu;
1559 netdev_state_change(dev);
1560 }
1561
1562 return 0;
1563}
1564
1565static size_t ipgre_get_size(const struct net_device *dev)
1566{
1567 return
1568 /* IFLA_GRE_LINK */
1569 nla_total_size(4) +
1570 /* IFLA_GRE_IFLAGS */
1571 nla_total_size(2) +
1572 /* IFLA_GRE_OFLAGS */
1573 nla_total_size(2) +
1574 /* IFLA_GRE_IKEY */
1575 nla_total_size(4) +
1576 /* IFLA_GRE_OKEY */
1577 nla_total_size(4) +
1578 /* IFLA_GRE_LOCAL */
1579 nla_total_size(4) +
1580 /* IFLA_GRE_REMOTE */
1581 nla_total_size(4) +
1582 /* IFLA_GRE_TTL */
1583 nla_total_size(1) +
1584 /* IFLA_GRE_TOS */
1585 nla_total_size(1) +
1586 /* IFLA_GRE_PMTUDISC */
1587 nla_total_size(1) +
1588 0;
1589}
1590
1591static int ipgre_fill_info(struct sk_buff *skb, const struct net_device *dev)
1592{
1593 struct ip_tunnel *t = netdev_priv(dev);
1594 struct ip_tunnel_parm *p = &t->parms;
1595
1596 NLA_PUT_U32(skb, IFLA_GRE_LINK, p->link);
1597 NLA_PUT_BE16(skb, IFLA_GRE_IFLAGS, p->i_flags);
1598 NLA_PUT_BE16(skb, IFLA_GRE_OFLAGS, p->o_flags);
Patrick McHardyba9e64b2008-10-10 12:10:30 -07001599 NLA_PUT_BE32(skb, IFLA_GRE_IKEY, p->i_key);
1600 NLA_PUT_BE32(skb, IFLA_GRE_OKEY, p->o_key);
Patrick McHardy4d74f8b2008-10-10 12:11:06 -07001601 NLA_PUT_BE32(skb, IFLA_GRE_LOCAL, p->iph.saddr);
1602 NLA_PUT_BE32(skb, IFLA_GRE_REMOTE, p->iph.daddr);
Herbert Xuc19e6542008-10-09 11:59:55 -07001603 NLA_PUT_U8(skb, IFLA_GRE_TTL, p->iph.ttl);
1604 NLA_PUT_U8(skb, IFLA_GRE_TOS, p->iph.tos);
1605 NLA_PUT_U8(skb, IFLA_GRE_PMTUDISC, !!(p->iph.frag_off & htons(IP_DF)));
1606
1607 return 0;
1608
1609nla_put_failure:
1610 return -EMSGSIZE;
1611}
1612
1613static const struct nla_policy ipgre_policy[IFLA_GRE_MAX + 1] = {
1614 [IFLA_GRE_LINK] = { .type = NLA_U32 },
1615 [IFLA_GRE_IFLAGS] = { .type = NLA_U16 },
1616 [IFLA_GRE_OFLAGS] = { .type = NLA_U16 },
1617 [IFLA_GRE_IKEY] = { .type = NLA_U32 },
1618 [IFLA_GRE_OKEY] = { .type = NLA_U32 },
Patrick McHardy4d74f8b2008-10-10 12:11:06 -07001619 [IFLA_GRE_LOCAL] = { .len = FIELD_SIZEOF(struct iphdr, saddr) },
1620 [IFLA_GRE_REMOTE] = { .len = FIELD_SIZEOF(struct iphdr, daddr) },
Herbert Xuc19e6542008-10-09 11:59:55 -07001621 [IFLA_GRE_TTL] = { .type = NLA_U8 },
1622 [IFLA_GRE_TOS] = { .type = NLA_U8 },
1623 [IFLA_GRE_PMTUDISC] = { .type = NLA_U8 },
1624};
1625
1626static struct rtnl_link_ops ipgre_link_ops __read_mostly = {
1627 .kind = "gre",
1628 .maxtype = IFLA_GRE_MAX,
1629 .policy = ipgre_policy,
1630 .priv_size = sizeof(struct ip_tunnel),
1631 .setup = ipgre_tunnel_setup,
1632 .validate = ipgre_tunnel_validate,
1633 .newlink = ipgre_newlink,
1634 .changelink = ipgre_changelink,
1635 .get_size = ipgre_get_size,
1636 .fill_info = ipgre_fill_info,
1637};
1638
Herbert Xue1a80002008-10-09 12:00:17 -07001639static struct rtnl_link_ops ipgre_tap_ops __read_mostly = {
1640 .kind = "gretap",
1641 .maxtype = IFLA_GRE_MAX,
1642 .policy = ipgre_policy,
1643 .priv_size = sizeof(struct ip_tunnel),
1644 .setup = ipgre_tap_setup,
1645 .validate = ipgre_tap_validate,
1646 .newlink = ipgre_newlink,
1647 .changelink = ipgre_changelink,
1648 .get_size = ipgre_get_size,
1649 .fill_info = ipgre_fill_info,
1650};
1651
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652/*
1653 * And now the modules code and kernel interface.
1654 */
1655
1656static int __init ipgre_init(void)
1657{
1658 int err;
1659
1660 printk(KERN_INFO "GRE over IPv4 tunneling driver\n");
1661
Eric W. Biedermancfb8fbf2009-11-29 15:46:13 +00001662 err = register_pernet_device(&ipgre_net_ops);
Pavel Emelyanov59a4c752008-04-16 01:08:53 -07001663 if (err < 0)
Alexey Dobriyanc2892f02010-02-16 07:57:44 +00001664 return err;
1665
Dmitry Kozlov00959ad2010-08-21 23:05:39 -07001666 err = gre_add_protocol(&ipgre_protocol, GREPROTO_CISCO);
Alexey Dobriyanc2892f02010-02-16 07:57:44 +00001667 if (err < 0) {
1668 printk(KERN_INFO "ipgre init: can't add protocol\n");
1669 goto add_proto_failed;
1670 }
Pavel Emelyanov7daa0002008-04-16 01:10:05 -07001671
Herbert Xuc19e6542008-10-09 11:59:55 -07001672 err = rtnl_link_register(&ipgre_link_ops);
1673 if (err < 0)
1674 goto rtnl_link_failed;
1675
Herbert Xue1a80002008-10-09 12:00:17 -07001676 err = rtnl_link_register(&ipgre_tap_ops);
1677 if (err < 0)
1678 goto tap_ops_failed;
1679
Herbert Xuc19e6542008-10-09 11:59:55 -07001680out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001681 return err;
Herbert Xuc19e6542008-10-09 11:59:55 -07001682
Herbert Xue1a80002008-10-09 12:00:17 -07001683tap_ops_failed:
1684 rtnl_link_unregister(&ipgre_link_ops);
Herbert Xuc19e6542008-10-09 11:59:55 -07001685rtnl_link_failed:
Dmitry Kozlov00959ad2010-08-21 23:05:39 -07001686 gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO);
Alexey Dobriyanc2892f02010-02-16 07:57:44 +00001687add_proto_failed:
1688 unregister_pernet_device(&ipgre_net_ops);
Herbert Xuc19e6542008-10-09 11:59:55 -07001689 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690}
1691
Alexey Kuznetsovdb445752005-07-30 17:46:44 -07001692static void __exit ipgre_fini(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693{
Herbert Xue1a80002008-10-09 12:00:17 -07001694 rtnl_link_unregister(&ipgre_tap_ops);
Herbert Xuc19e6542008-10-09 11:59:55 -07001695 rtnl_link_unregister(&ipgre_link_ops);
Dmitry Kozlov00959ad2010-08-21 23:05:39 -07001696 if (gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO) < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697 printk(KERN_INFO "ipgre close: can't remove protocol\n");
Alexey Dobriyanc2892f02010-02-16 07:57:44 +00001698 unregister_pernet_device(&ipgre_net_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699}
1700
1701module_init(ipgre_init);
1702module_exit(ipgre_fini);
1703MODULE_LICENSE("GPL");
Patrick McHardy4d74f8b2008-10-10 12:11:06 -07001704MODULE_ALIAS_RTNL_LINK("gre");
1705MODULE_ALIAS_RTNL_LINK("gretap");