blob: d7aea4c5b9400efec37d15db3c5a896769d0da68 [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
Joe Perchesafd465032012-03-12 07:03:32 +000013#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
14
Randy Dunlap4fc268d2006-01-11 12:17:47 -080015#include <linux/capability.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070016#include <linux/module.h>
17#include <linux/types.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070018#include <linux/kernel.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090019#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070020#include <asm/uaccess.h>
21#include <linux/skbuff.h>
22#include <linux/netdevice.h>
23#include <linux/in.h>
24#include <linux/tcp.h>
25#include <linux/udp.h>
26#include <linux/if_arp.h>
27#include <linux/mroute.h>
28#include <linux/init.h>
29#include <linux/in6.h>
30#include <linux/inetdevice.h>
31#include <linux/igmp.h>
32#include <linux/netfilter_ipv4.h>
Herbert Xue1a80002008-10-09 12:00:17 -070033#include <linux/etherdevice.h>
Kris Katterjohn46f25df2006-01-05 16:35:42 -080034#include <linux/if_ether.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070035
36#include <net/sock.h>
37#include <net/ip.h>
38#include <net/icmp.h>
39#include <net/protocol.h>
Pravin B Shelarc5441932013-03-25 14:49:35 +000040#include <net/ip_tunnels.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070041#include <net/arp.h>
42#include <net/checksum.h>
43#include <net/dsfield.h>
44#include <net/inet_ecn.h>
45#include <net/xfrm.h>
Pavel Emelyanov59a4c752008-04-16 01:08:53 -070046#include <net/net_namespace.h>
47#include <net/netns/generic.h>
Herbert Xuc19e6542008-10-09 11:59:55 -070048#include <net/rtnetlink.h>
Dmitry Kozlov00959ad2010-08-21 23:05:39 -070049#include <net/gre.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070050
Eric Dumazetdfd56b82011-12-10 09:48:31 +000051#if IS_ENABLED(CONFIG_IPV6)
Linus Torvalds1da177e2005-04-16 15:20:36 -070052#include <net/ipv6.h>
53#include <net/ip6_fib.h>
54#include <net/ip6_route.h>
55#endif
56
57/*
58 Problems & solutions
59 --------------------
60
61 1. The most important issue is detecting local dead loops.
62 They would cause complete host lockup in transmit, which
63 would be "resolved" by stack overflow or, if queueing is enabled,
64 with infinite looping in net_bh.
65
66 We cannot track such dead loops during route installation,
67 it is infeasible task. The most general solutions would be
68 to keep skb->encapsulation counter (sort of local ttl),
Eric Dumazet6d0722a2010-09-29 23:35:10 -070069 and silently drop packet when it expires. It is a good
stephen hemmingerbff52852012-02-24 08:08:20 +000070 solution, but it supposes maintaining new variable in ALL
Linus Torvalds1da177e2005-04-16 15:20:36 -070071 skb, even if no tunneling is used.
72
Eric Dumazet6d0722a2010-09-29 23:35:10 -070073 Current solution: xmit_recursion breaks dead loops. This is a percpu
74 counter, since when we enter the first ndo_xmit(), cpu migration is
75 forbidden. We force an exit if this counter reaches RECURSION_LIMIT
Linus Torvalds1da177e2005-04-16 15:20:36 -070076
77 2. Networking dead loops would not kill routers, but would really
78 kill network. IP hop limit plays role of "t->recursion" in this case,
79 if we copy it from packet being encapsulated to upper header.
80 It is very good solution, but it introduces two problems:
81
82 - Routing protocols, using packets with ttl=1 (OSPF, RIP2),
83 do not work over tunnels.
84 - traceroute does not work. I planned to relay ICMP from tunnel,
85 so that this problem would be solved and traceroute output
86 would even more informative. This idea appeared to be wrong:
87 only Linux complies to rfc1812 now (yes, guys, Linux is the only
88 true router now :-)), all routers (at least, in neighbourhood of mine)
89 return only 8 bytes of payload. It is the end.
90
91 Hence, if we want that OSPF worked or traceroute said something reasonable,
92 we should search for another solution.
93
94 One of them is to parse packet trying to detect inner encapsulation
95 made by our node. It is difficult or even impossible, especially,
stephen hemmingerbff52852012-02-24 08:08:20 +000096 taking into account fragmentation. TO be short, ttl is not solution at all.
Linus Torvalds1da177e2005-04-16 15:20:36 -070097
98 Current solution: The solution was UNEXPECTEDLY SIMPLE.
99 We force DF flag on tunnels with preconfigured hop limit,
100 that is ALL. :-) Well, it does not remove the problem completely,
101 but exponential growth of network traffic is changed to linear
102 (branches, that exceed pmtu are pruned) and tunnel mtu
stephen hemmingerbff52852012-02-24 08:08:20 +0000103 rapidly degrades to value <68, where looping stops.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104 Yes, it is not good if there exists a router in the loop,
105 which does not force DF, even when encapsulating packets have DF set.
106 But it is not our problem! Nobody could accuse us, we made
107 all that we could make. Even if it is your gated who injected
108 fatal route to network, even if it were you who configured
109 fatal static route: you are innocent. :-)
110
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111 Alexey Kuznetsov.
112 */
113
stephen hemmingereccc1bb2012-09-25 11:02:48 +0000114static bool log_ecn_error = true;
115module_param(log_ecn_error, bool, 0644);
116MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN");
117
Herbert Xuc19e6542008-10-09 11:59:55 -0700118static struct rtnl_link_ops ipgre_link_ops __read_mostly;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119static int ipgre_tunnel_init(struct net_device *dev);
Pavel Emelyanoveb8ce742008-04-16 01:10:26 -0700120
Eric Dumazetf99189b2009-11-17 10:42:49 +0000121static int ipgre_net_id __read_mostly;
Pravin B Shelarc5441932013-03-25 14:49:35 +0000122static int gre_tap_net_id __read_mostly;
Pavel Emelyanoveb8ce742008-04-16 01:10:26 -0700123
Pravin B Shelarbda7bb42013-06-17 17:49:38 -0700124static int ipgre_err(struct sk_buff *skb, u32 info,
125 const struct tnl_ptk_info *tpi)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127
Pravin B Shelarc5441932013-03-25 14:49:35 +0000128 /* All the routers (except for Linux) return only
129 8 bytes of packet payload. It means, that precise relaying of
130 ICMP in the real Internet is absolutely infeasible.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131
Pravin B Shelarc5441932013-03-25 14:49:35 +0000132 Moreover, Cisco "wise men" put GRE key to the third word
133 in GRE header. It makes impossible maintaining even soft
134 state for keyed GRE tunnels with enabled checksum. Tell
135 them "thank you".
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136
Pravin B Shelarc5441932013-03-25 14:49:35 +0000137 Well, I wonder, rfc1812 was written by Cisco employee,
138 what the hell these idiots break standards established
139 by themselves???
140 */
141 struct net *net = dev_net(skb->dev);
142 struct ip_tunnel_net *itn;
Eric Dumazet96f5a842013-05-18 08:36:03 +0000143 const struct iphdr *iph;
Arnaldo Carvalho de Melo88c76642007-03-13 14:43:18 -0300144 const int type = icmp_hdr(skb)->type;
145 const int code = icmp_hdr(skb)->code;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146 struct ip_tunnel *t;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148 switch (type) {
149 default:
150 case ICMP_PARAMETERPROB:
Pravin B Shelarbda7bb42013-06-17 17:49:38 -0700151 return PACKET_RCVD;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152
153 case ICMP_DEST_UNREACH:
154 switch (code) {
155 case ICMP_SR_FAILED:
156 case ICMP_PORT_UNREACH:
157 /* Impossible event. */
Pravin B Shelarbda7bb42013-06-17 17:49:38 -0700158 return PACKET_RCVD;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 default:
160 /* All others are translated to HOST_UNREACH.
161 rfc2003 contains "deep thoughts" about NET_UNREACH,
162 I believe they are just ether pollution. --ANK
163 */
164 break;
165 }
166 break;
167 case ICMP_TIME_EXCEEDED:
168 if (code != ICMP_EXC_TTL)
Pravin B Shelarbda7bb42013-06-17 17:49:38 -0700169 return PACKET_RCVD;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170 break;
David S. Miller55be7a92012-07-11 21:27:49 -0700171
172 case ICMP_REDIRECT:
173 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174 }
175
Pravin B Shelarbda7bb42013-06-17 17:49:38 -0700176 if (tpi->proto == htons(ETH_P_TEB))
Pravin B Shelarc5441932013-03-25 14:49:35 +0000177 itn = net_generic(net, gre_tap_net_id);
178 else
179 itn = net_generic(net, ipgre_net_id);
180
Eric Dumazet96f5a842013-05-18 08:36:03 +0000181 iph = (const struct iphdr *)skb->data;
Pravin B Shelarbda7bb42013-06-17 17:49:38 -0700182 t = ip_tunnel_lookup(itn, skb->dev->ifindex, tpi->flags,
183 iph->daddr, iph->saddr, tpi->key);
stephen hemmingerd2083282012-09-24 18:12:23 +0000184
David S. Miller36393392012-06-14 22:21:46 -0700185 if (t == NULL)
Pravin B Shelarbda7bb42013-06-17 17:49:38 -0700186 return PACKET_REJECT;
David S. Miller36393392012-06-14 22:21:46 -0700187
David S. Miller36393392012-06-14 22:21:46 -0700188 if (t->parms.iph.daddr == 0 ||
Joe Perchesf97c1e02007-12-16 13:45:43 -0800189 ipv4_is_multicast(t->parms.iph.daddr))
Pravin B Shelarbda7bb42013-06-17 17:49:38 -0700190 return PACKET_RCVD;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191
192 if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED)
Pravin B Shelarbda7bb42013-06-17 17:49:38 -0700193 return PACKET_RCVD;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194
Wei Yongjunda6185d82009-02-24 23:34:48 -0800195 if (time_before(jiffies, t->err_time + IPTUNNEL_ERR_TIMEO))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196 t->err_count++;
197 else
198 t->err_count = 1;
199 t->err_time = jiffies;
Pravin B Shelarbda7bb42013-06-17 17:49:38 -0700200 return PACKET_RCVD;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201}
202
Pravin B Shelarbda7bb42013-06-17 17:49:38 -0700203static int ipgre_rcv(struct sk_buff *skb, const struct tnl_ptk_info *tpi)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204{
Pravin B Shelarc5441932013-03-25 14:49:35 +0000205 struct net *net = dev_net(skb->dev);
206 struct ip_tunnel_net *itn;
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000207 const struct iphdr *iph;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 struct ip_tunnel *tunnel;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209
Pravin B Shelarbda7bb42013-06-17 17:49:38 -0700210 if (tpi->proto == htons(ETH_P_TEB))
Pravin B Shelarc5441932013-03-25 14:49:35 +0000211 itn = net_generic(net, gre_tap_net_id);
212 else
213 itn = net_generic(net, ipgre_net_id);
214
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700215 iph = ip_hdr(skb);
Pravin B Shelarbda7bb42013-06-17 17:49:38 -0700216 tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, tpi->flags,
217 iph->saddr, iph->daddr, tpi->key);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218
stephen hemmingerd2083282012-09-24 18:12:23 +0000219 if (tunnel) {
Pravin B Shelarbda7bb42013-06-17 17:49:38 -0700220 ip_tunnel_rcv(tunnel, skb, tpi, log_ecn_error);
221 return PACKET_RCVD;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 }
Pravin B Shelarbda7bb42013-06-17 17:49:38 -0700223 return PACKET_REJECT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224}
225
Pravin B Shelarc5441932013-03-25 14:49:35 +0000226static void __gre_xmit(struct sk_buff *skb, struct net_device *dev,
227 const struct iphdr *tnl_params,
228 __be16 proto)
229{
230 struct ip_tunnel *tunnel = netdev_priv(dev);
231 struct tnl_ptk_info tpi;
232
Pravin B Shelarc5441932013-03-25 14:49:35 +0000233 tpi.flags = tunnel->parms.o_flags;
234 tpi.proto = proto;
235 tpi.key = tunnel->parms.o_key;
236 if (tunnel->parms.o_flags & TUNNEL_SEQ)
237 tunnel->o_seqno++;
238 tpi.seq = htonl(tunnel->o_seqno);
Eric Dumazetcef401d2013-01-25 20:34:37 +0000239
Pravin B Shelarc5441932013-03-25 14:49:35 +0000240 /* Push GRE header. */
Pravin B Shelar752f36d2013-06-17 17:49:45 -0700241 gre_build_header(skb, &tpi, tunnel->hlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242
Nicolas Dichtelbf3d6a82013-05-27 23:48:15 +0000243 ip_tunnel_xmit(skb, dev, tnl_params, tnl_params->protocol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244}
245
Pravin B Shelarc5441932013-03-25 14:49:35 +0000246static netdev_tx_t ipgre_xmit(struct sk_buff *skb,
247 struct net_device *dev)
Michal Schmidtee34c1e2007-12-13 09:46:32 -0800248{
Pravin B Shelarc5441932013-03-25 14:49:35 +0000249 struct ip_tunnel *tunnel = netdev_priv(dev);
250 const struct iphdr *tnl_params;
Michal Schmidtee34c1e2007-12-13 09:46:32 -0800251
Pravin B Shelar45f2e992013-06-17 17:49:51 -0700252 skb = gre_handle_offloads(skb, !!(tunnel->parms.o_flags&TUNNEL_CSUM));
Pravin B Shelarc5441932013-03-25 14:49:35 +0000253 if (IS_ERR(skb))
254 goto out;
Michal Schmidtee34c1e2007-12-13 09:46:32 -0800255
Pravin B Shelarc5441932013-03-25 14:49:35 +0000256 if (dev->header_ops) {
257 /* Need space for new headers */
258 if (skb_cow_head(skb, dev->needed_headroom -
Chen Gang2bac7cb2013-04-22 20:45:42 +0000259 (tunnel->hlen + sizeof(struct iphdr))))
Pravin B Shelarc5441932013-03-25 14:49:35 +0000260 goto free_skb;
Michal Schmidtee34c1e2007-12-13 09:46:32 -0800261
Pravin B Shelarc5441932013-03-25 14:49:35 +0000262 tnl_params = (const struct iphdr *)skb->data;
Eric Dumazete985aad2010-09-27 03:57:11 +0000263
Pravin B Shelarc5441932013-03-25 14:49:35 +0000264 /* Pull skb since ip_tunnel_xmit() needs skb->data pointing
265 * to gre header.
266 */
267 skb_pull(skb, tunnel->hlen + sizeof(struct iphdr));
268 } else {
269 if (skb_cow_head(skb, dev->needed_headroom))
270 goto free_skb;
Herbert Xue1a80002008-10-09 12:00:17 -0700271
Pravin B Shelarc5441932013-03-25 14:49:35 +0000272 tnl_params = &tunnel->parms.iph;
Michal Schmidtee34c1e2007-12-13 09:46:32 -0800273 }
274
Pravin B Shelarc5441932013-03-25 14:49:35 +0000275 __gre_xmit(skb, dev, tnl_params, skb->protocol);
Michal Schmidtee34c1e2007-12-13 09:46:32 -0800276
Pravin B Shelarc5441932013-03-25 14:49:35 +0000277 return NETDEV_TX_OK;
Michal Schmidtee34c1e2007-12-13 09:46:32 -0800278
Pravin B Shelarc5441932013-03-25 14:49:35 +0000279free_skb:
280 dev_kfree_skb(skb);
281out:
282 dev->stats.tx_dropped++;
283 return NETDEV_TX_OK;
Michal Schmidtee34c1e2007-12-13 09:46:32 -0800284}
285
Pravin B Shelarc5441932013-03-25 14:49:35 +0000286static netdev_tx_t gre_tap_xmit(struct sk_buff *skb,
287 struct net_device *dev)
288{
289 struct ip_tunnel *tunnel = netdev_priv(dev);
290
Pravin B Shelar45f2e992013-06-17 17:49:51 -0700291 skb = gre_handle_offloads(skb, !!(tunnel->parms.o_flags&TUNNEL_CSUM));
Pravin B Shelarc5441932013-03-25 14:49:35 +0000292 if (IS_ERR(skb))
293 goto out;
294
295 if (skb_cow_head(skb, dev->needed_headroom))
296 goto free_skb;
297
298 __gre_xmit(skb, dev, &tunnel->parms.iph, htons(ETH_P_TEB));
299
300 return NETDEV_TX_OK;
301
302free_skb:
303 dev_kfree_skb(skb);
304out:
305 dev->stats.tx_dropped++;
306 return NETDEV_TX_OK;
307}
308
309static int ipgre_tunnel_ioctl(struct net_device *dev,
310 struct ifreq *ifr, int cmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311{
312 int err = 0;
313 struct ip_tunnel_parm p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314
Pravin B Shelarc5441932013-03-25 14:49:35 +0000315 if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
316 return -EFAULT;
Cong Wang6c734fb2013-06-29 12:02:59 +0800317 if (cmd == SIOCADDTUNNEL || cmd == SIOCCHGTUNNEL) {
318 if (p.iph.version != 4 || p.iph.protocol != IPPROTO_GRE ||
319 p.iph.ihl != 5 || (p.iph.frag_off&htons(~IP_DF)) ||
320 ((p.i_flags|p.o_flags)&(GRE_VERSION|GRE_ROUTING)))
321 return -EINVAL;
Pravin B Shelarc5441932013-03-25 14:49:35 +0000322 }
323 p.i_flags = gre_flags_to_tnl_flags(p.i_flags);
324 p.o_flags = gre_flags_to_tnl_flags(p.o_flags);
325
326 err = ip_tunnel_ioctl(dev, &p, cmd);
327 if (err)
328 return err;
329
330 p.i_flags = tnl_flags_to_gre_flags(p.i_flags);
331 p.o_flags = tnl_flags_to_gre_flags(p.o_flags);
332
333 if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p)))
334 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335 return 0;
336}
337
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338/* Nice toy. Unfortunately, useless in real life :-)
339 It allows to construct virtual multiprotocol broadcast "LAN"
340 over the Internet, provided multicast routing is tuned.
341
342
343 I have no idea was this bicycle invented before me,
344 so that I had to set ARPHRD_IPGRE to a random value.
345 I have an impression, that Cisco could make something similar,
346 but this feature is apparently missing in IOS<=11.2(8).
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900347
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 I set up 10.66.66/24 and fec0:6666:6666::0/96 as virtual networks
349 with broadcast 224.66.66.66. If you have access to mbone, play with me :-)
350
351 ping -t 255 224.66.66.66
352
353 If nobody answers, mbone does not work.
354
355 ip tunnel add Universe mode gre remote 224.66.66.66 local <Your_real_addr> ttl 255
356 ip addr add 10.66.66.<somewhat>/24 dev Universe
357 ifconfig Universe up
358 ifconfig Universe add fe80::<Your_real_addr>/10
359 ifconfig Universe add fec0:6666:6666::<Your_real_addr>/96
360 ftp 10.66.66.66
361 ...
362 ftp fec0:6666:6666::193.233.7.65
363 ...
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364 */
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -0700365static int ipgre_header(struct sk_buff *skb, struct net_device *dev,
366 unsigned short type,
Eric Dumazet15078502010-09-15 11:07:53 +0000367 const void *daddr, const void *saddr, unsigned int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368{
Patrick McHardy2941a482006-01-08 22:05:26 -0800369 struct ip_tunnel *t = netdev_priv(dev);
Pravin B Shelarc5441932013-03-25 14:49:35 +0000370 struct iphdr *iph;
371 struct gre_base_hdr *greh;
372
373 iph = (struct iphdr *)skb_push(skb, t->hlen + sizeof(*iph));
374 greh = (struct gre_base_hdr *)(iph+1);
375 greh->flags = tnl_flags_to_gre_flags(t->parms.o_flags);
376 greh->protocol = htons(type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377
378 memcpy(iph, &t->parms.iph, sizeof(struct iphdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379
Pravin B Shelarc5441932013-03-25 14:49:35 +0000380 /* Set the source hardware address. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381 if (saddr)
382 memcpy(&iph->saddr, saddr, 4);
Timo Teräs6d55cb92010-03-03 04:01:13 +0000383 if (daddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 memcpy(&iph->daddr, daddr, 4);
Timo Teräs6d55cb92010-03-03 04:01:13 +0000385 if (iph->daddr)
Timo Teräs77a482b2013-08-06 13:45:43 +0300386 return t->hlen + sizeof(*iph);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900387
Pravin B Shelarc5441932013-03-25 14:49:35 +0000388 return -(t->hlen + sizeof(*iph));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389}
390
Timo Teras6a5f44d2007-10-23 20:31:53 -0700391static int ipgre_header_parse(const struct sk_buff *skb, unsigned char *haddr)
392{
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000393 const struct iphdr *iph = (const struct iphdr *) skb_mac_header(skb);
Timo Teras6a5f44d2007-10-23 20:31:53 -0700394 memcpy(haddr, &iph->saddr, 4);
395 return 4;
396}
397
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -0700398static const struct header_ops ipgre_header_ops = {
399 .create = ipgre_header,
Timo Teras6a5f44d2007-10-23 20:31:53 -0700400 .parse = ipgre_header_parse,
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -0700401};
402
Timo Teras6a5f44d2007-10-23 20:31:53 -0700403#ifdef CONFIG_NET_IPGRE_BROADCAST
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404static int ipgre_open(struct net_device *dev)
405{
Patrick McHardy2941a482006-01-08 22:05:26 -0800406 struct ip_tunnel *t = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407
Joe Perchesf97c1e02007-12-16 13:45:43 -0800408 if (ipv4_is_multicast(t->parms.iph.daddr)) {
David S. Millercbb1e852011-05-04 12:33:34 -0700409 struct flowi4 fl4;
410 struct rtable *rt;
Eric Dumazete985aad2010-09-27 03:57:11 +0000411
David S. Millercbb1e852011-05-04 12:33:34 -0700412 rt = ip_route_output_gre(dev_net(dev), &fl4,
413 t->parms.iph.daddr,
414 t->parms.iph.saddr,
415 t->parms.o_key,
416 RT_TOS(t->parms.iph.tos),
417 t->parms.link);
David S. Millerb23dd4f2011-03-02 14:31:35 -0800418 if (IS_ERR(rt))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 return -EADDRNOTAVAIL;
Changli Gaod8d1f302010-06-10 23:31:35 -0700420 dev = rt->dst.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 ip_rt_put(rt);
Herbert Xue5ed6392005-10-03 14:35:55 -0700422 if (__in_dev_get_rtnl(dev) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 return -EADDRNOTAVAIL;
424 t->mlink = dev->ifindex;
Herbert Xue5ed6392005-10-03 14:35:55 -0700425 ip_mc_inc_group(__in_dev_get_rtnl(dev), t->parms.iph.daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 }
427 return 0;
428}
429
430static int ipgre_close(struct net_device *dev)
431{
Patrick McHardy2941a482006-01-08 22:05:26 -0800432 struct ip_tunnel *t = netdev_priv(dev);
Stephen Hemmingerb8c26a32008-11-20 20:34:29 -0800433
Joe Perchesf97c1e02007-12-16 13:45:43 -0800434 if (ipv4_is_multicast(t->parms.iph.daddr) && t->mlink) {
Denis V. Lunev7fee0ca2008-01-21 17:32:38 -0800435 struct in_device *in_dev;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900436 in_dev = inetdev_by_index(dev_net(dev), t->mlink);
Eric Dumazet8723e1b2010-10-19 00:39:26 +0000437 if (in_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 ip_mc_dec_group(in_dev, t->parms.iph.daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 }
440 return 0;
441}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442#endif
443
Stephen Hemmingerb8c26a32008-11-20 20:34:29 -0800444static const struct net_device_ops ipgre_netdev_ops = {
445 .ndo_init = ipgre_tunnel_init,
Pravin B Shelarc5441932013-03-25 14:49:35 +0000446 .ndo_uninit = ip_tunnel_uninit,
Stephen Hemmingerb8c26a32008-11-20 20:34:29 -0800447#ifdef CONFIG_NET_IPGRE_BROADCAST
448 .ndo_open = ipgre_open,
449 .ndo_stop = ipgre_close,
450#endif
Pravin B Shelarc5441932013-03-25 14:49:35 +0000451 .ndo_start_xmit = ipgre_xmit,
Stephen Hemmingerb8c26a32008-11-20 20:34:29 -0800452 .ndo_do_ioctl = ipgre_tunnel_ioctl,
Pravin B Shelarc5441932013-03-25 14:49:35 +0000453 .ndo_change_mtu = ip_tunnel_change_mtu,
454 .ndo_get_stats64 = ip_tunnel_get_stats64,
Stephen Hemmingerb8c26a32008-11-20 20:34:29 -0800455};
456
Eric Dumazet6b78f162012-09-13 21:25:33 +0000457#define GRE_FEATURES (NETIF_F_SG | \
458 NETIF_F_FRAGLIST | \
459 NETIF_F_HIGHDMA | \
460 NETIF_F_HW_CSUM)
461
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462static void ipgre_tunnel_setup(struct net_device *dev)
463{
Stephen Hemmingerb8c26a32008-11-20 20:34:29 -0800464 dev->netdev_ops = &ipgre_netdev_ops;
Pravin B Shelarc5441932013-03-25 14:49:35 +0000465 ip_tunnel_setup(dev, ipgre_net_id);
466}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467
Pravin B Shelarc5441932013-03-25 14:49:35 +0000468static void __gre_tunnel_init(struct net_device *dev)
469{
470 struct ip_tunnel *tunnel;
471
472 tunnel = netdev_priv(dev);
473 tunnel->hlen = ip_gre_calc_hlen(tunnel->parms.o_flags);
474 tunnel->parms.iph.protocol = IPPROTO_GRE;
475
476 dev->needed_headroom = LL_MAX_HEADER + sizeof(struct iphdr) + 4;
Kris Katterjohn46f25df2006-01-05 16:35:42 -0800477 dev->mtu = ETH_DATA_LEN - sizeof(struct iphdr) - 4;
Eric Dumazet6b78f162012-09-13 21:25:33 +0000478
Pravin B Shelarc5441932013-03-25 14:49:35 +0000479 dev->features |= NETIF_F_NETNS_LOCAL | GRE_FEATURES;
Eric Dumazet6b78f162012-09-13 21:25:33 +0000480 dev->hw_features |= GRE_FEATURES;
Pravin B Shelarc5441932013-03-25 14:49:35 +0000481
482 if (!(tunnel->parms.o_flags & TUNNEL_SEQ)) {
483 /* TCP offload with GRE SEQ is not supported. */
484 dev->features |= NETIF_F_GSO_SOFTWARE;
485 dev->hw_features |= NETIF_F_GSO_SOFTWARE;
486 /* Can use a lockless transmit, unless we generate
487 * output sequences
488 */
489 dev->features |= NETIF_F_LLTX;
490 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491}
492
493static int ipgre_tunnel_init(struct net_device *dev)
494{
Pravin B Shelarc5441932013-03-25 14:49:35 +0000495 struct ip_tunnel *tunnel = netdev_priv(dev);
496 struct iphdr *iph = &tunnel->parms.iph;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497
Pravin B Shelarc5441932013-03-25 14:49:35 +0000498 __gre_tunnel_init(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499
Pravin B Shelarc5441932013-03-25 14:49:35 +0000500 memcpy(dev->dev_addr, &iph->saddr, 4);
501 memcpy(dev->broadcast, &iph->daddr, 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502
Pravin B Shelarc5441932013-03-25 14:49:35 +0000503 dev->type = ARPHRD_IPGRE;
504 dev->flags = IFF_NOARP;
505 dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
506 dev->addr_len = 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508 if (iph->daddr) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509#ifdef CONFIG_NET_IPGRE_BROADCAST
Joe Perchesf97c1e02007-12-16 13:45:43 -0800510 if (ipv4_is_multicast(iph->daddr)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511 if (!iph->saddr)
512 return -EINVAL;
513 dev->flags = IFF_BROADCAST;
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -0700514 dev->header_ops = &ipgre_header_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 }
516#endif
Michal Schmidtee34c1e2007-12-13 09:46:32 -0800517 } else
Timo Teras6a5f44d2007-10-23 20:31:53 -0700518 dev->header_ops = &ipgre_header_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519
Pravin B Shelarc5441932013-03-25 14:49:35 +0000520 return ip_tunnel_init(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521}
522
Pravin B Shelarbda7bb42013-06-17 17:49:38 -0700523static struct gre_cisco_protocol ipgre_protocol = {
524 .handler = ipgre_rcv,
525 .err_handler = ipgre_err,
526 .priority = 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527};
528
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +0000529static int __net_init ipgre_init_net(struct net *net)
Pavel Emelyanov59a4c752008-04-16 01:08:53 -0700530{
Pravin B Shelarc5441932013-03-25 14:49:35 +0000531 return ip_tunnel_init_net(net, ipgre_net_id, &ipgre_link_ops, NULL);
Pavel Emelyanov59a4c752008-04-16 01:08:53 -0700532}
533
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +0000534static void __net_exit ipgre_exit_net(struct net *net)
Pavel Emelyanov59a4c752008-04-16 01:08:53 -0700535{
Pravin B Shelarc5441932013-03-25 14:49:35 +0000536 struct ip_tunnel_net *itn = net_generic(net, ipgre_net_id);
Nicolas Dichtel6c742e72013-08-13 17:51:11 +0200537 ip_tunnel_delete_net(itn, &ipgre_link_ops);
Pavel Emelyanov59a4c752008-04-16 01:08:53 -0700538}
539
540static struct pernet_operations ipgre_net_ops = {
541 .init = ipgre_init_net,
542 .exit = ipgre_exit_net,
Eric W. Biedermancfb8fbf2009-11-29 15:46:13 +0000543 .id = &ipgre_net_id,
Pravin B Shelarc5441932013-03-25 14:49:35 +0000544 .size = sizeof(struct ip_tunnel_net),
Pavel Emelyanov59a4c752008-04-16 01:08:53 -0700545};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546
Herbert Xuc19e6542008-10-09 11:59:55 -0700547static int ipgre_tunnel_validate(struct nlattr *tb[], struct nlattr *data[])
548{
549 __be16 flags;
550
551 if (!data)
552 return 0;
553
554 flags = 0;
555 if (data[IFLA_GRE_IFLAGS])
556 flags |= nla_get_be16(data[IFLA_GRE_IFLAGS]);
557 if (data[IFLA_GRE_OFLAGS])
558 flags |= nla_get_be16(data[IFLA_GRE_OFLAGS]);
559 if (flags & (GRE_VERSION|GRE_ROUTING))
560 return -EINVAL;
561
562 return 0;
563}
564
Herbert Xue1a80002008-10-09 12:00:17 -0700565static int ipgre_tap_validate(struct nlattr *tb[], struct nlattr *data[])
566{
567 __be32 daddr;
568
569 if (tb[IFLA_ADDRESS]) {
570 if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN)
571 return -EINVAL;
572 if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS])))
573 return -EADDRNOTAVAIL;
574 }
575
576 if (!data)
577 goto out;
578
579 if (data[IFLA_GRE_REMOTE]) {
580 memcpy(&daddr, nla_data(data[IFLA_GRE_REMOTE]), 4);
581 if (!daddr)
582 return -EINVAL;
583 }
584
585out:
586 return ipgre_tunnel_validate(tb, data);
587}
588
Pravin B Shelarc5441932013-03-25 14:49:35 +0000589static void ipgre_netlink_parms(struct nlattr *data[], struct nlattr *tb[],
590 struct ip_tunnel_parm *parms)
Herbert Xuc19e6542008-10-09 11:59:55 -0700591{
Herbert Xu7bb82d92008-10-11 12:20:15 -0700592 memset(parms, 0, sizeof(*parms));
Herbert Xuc19e6542008-10-09 11:59:55 -0700593
594 parms->iph.protocol = IPPROTO_GRE;
595
596 if (!data)
597 return;
598
599 if (data[IFLA_GRE_LINK])
600 parms->link = nla_get_u32(data[IFLA_GRE_LINK]);
601
602 if (data[IFLA_GRE_IFLAGS])
Pravin B Shelarc5441932013-03-25 14:49:35 +0000603 parms->i_flags = gre_flags_to_tnl_flags(nla_get_be16(data[IFLA_GRE_IFLAGS]));
Herbert Xuc19e6542008-10-09 11:59:55 -0700604
605 if (data[IFLA_GRE_OFLAGS])
Pravin B Shelarc5441932013-03-25 14:49:35 +0000606 parms->o_flags = gre_flags_to_tnl_flags(nla_get_be16(data[IFLA_GRE_OFLAGS]));
Herbert Xuc19e6542008-10-09 11:59:55 -0700607
608 if (data[IFLA_GRE_IKEY])
609 parms->i_key = nla_get_be32(data[IFLA_GRE_IKEY]);
610
611 if (data[IFLA_GRE_OKEY])
612 parms->o_key = nla_get_be32(data[IFLA_GRE_OKEY]);
613
614 if (data[IFLA_GRE_LOCAL])
Patrick McHardy4d74f8b2008-10-10 12:11:06 -0700615 parms->iph.saddr = nla_get_be32(data[IFLA_GRE_LOCAL]);
Herbert Xuc19e6542008-10-09 11:59:55 -0700616
617 if (data[IFLA_GRE_REMOTE])
Patrick McHardy4d74f8b2008-10-10 12:11:06 -0700618 parms->iph.daddr = nla_get_be32(data[IFLA_GRE_REMOTE]);
Herbert Xuc19e6542008-10-09 11:59:55 -0700619
620 if (data[IFLA_GRE_TTL])
621 parms->iph.ttl = nla_get_u8(data[IFLA_GRE_TTL]);
622
623 if (data[IFLA_GRE_TOS])
624 parms->iph.tos = nla_get_u8(data[IFLA_GRE_TOS]);
625
626 if (!data[IFLA_GRE_PMTUDISC] || nla_get_u8(data[IFLA_GRE_PMTUDISC]))
627 parms->iph.frag_off = htons(IP_DF);
628}
629
Pravin B Shelarc5441932013-03-25 14:49:35 +0000630static int gre_tap_init(struct net_device *dev)
Herbert Xue1a80002008-10-09 12:00:17 -0700631{
Pravin B Shelarc5441932013-03-25 14:49:35 +0000632 __gre_tunnel_init(dev);
Herbert Xue1a80002008-10-09 12:00:17 -0700633
Pravin B Shelarc5441932013-03-25 14:49:35 +0000634 return ip_tunnel_init(dev);
Herbert Xue1a80002008-10-09 12:00:17 -0700635}
636
Pravin B Shelarc5441932013-03-25 14:49:35 +0000637static const struct net_device_ops gre_tap_netdev_ops = {
638 .ndo_init = gre_tap_init,
639 .ndo_uninit = ip_tunnel_uninit,
640 .ndo_start_xmit = gre_tap_xmit,
Stephen Hemmingerb8c26a32008-11-20 20:34:29 -0800641 .ndo_set_mac_address = eth_mac_addr,
642 .ndo_validate_addr = eth_validate_addr,
Pravin B Shelarc5441932013-03-25 14:49:35 +0000643 .ndo_change_mtu = ip_tunnel_change_mtu,
644 .ndo_get_stats64 = ip_tunnel_get_stats64,
Stephen Hemmingerb8c26a32008-11-20 20:34:29 -0800645};
646
Herbert Xue1a80002008-10-09 12:00:17 -0700647static void ipgre_tap_setup(struct net_device *dev)
648{
Herbert Xue1a80002008-10-09 12:00:17 -0700649 ether_setup(dev);
Pravin B Shelarc5441932013-03-25 14:49:35 +0000650 dev->netdev_ops = &gre_tap_netdev_ops;
651 ip_tunnel_setup(dev, gre_tap_net_id);
Herbert Xue1a80002008-10-09 12:00:17 -0700652}
653
Pravin B Shelarc5441932013-03-25 14:49:35 +0000654static int ipgre_newlink(struct net *src_net, struct net_device *dev,
655 struct nlattr *tb[], struct nlattr *data[])
Herbert Xuc19e6542008-10-09 11:59:55 -0700656{
Pravin B Shelarc5441932013-03-25 14:49:35 +0000657 struct ip_tunnel_parm p;
Herbert Xuc19e6542008-10-09 11:59:55 -0700658
Pravin B Shelarc5441932013-03-25 14:49:35 +0000659 ipgre_netlink_parms(data, tb, &p);
660 return ip_tunnel_newlink(dev, tb, &p);
Herbert Xuc19e6542008-10-09 11:59:55 -0700661}
662
663static int ipgre_changelink(struct net_device *dev, struct nlattr *tb[],
664 struct nlattr *data[])
665{
Herbert Xuc19e6542008-10-09 11:59:55 -0700666 struct ip_tunnel_parm p;
Herbert Xuc19e6542008-10-09 11:59:55 -0700667
Pravin B Shelarc5441932013-03-25 14:49:35 +0000668 ipgre_netlink_parms(data, tb, &p);
669 return ip_tunnel_changelink(dev, tb, &p);
Herbert Xuc19e6542008-10-09 11:59:55 -0700670}
671
672static size_t ipgre_get_size(const struct net_device *dev)
673{
674 return
675 /* IFLA_GRE_LINK */
676 nla_total_size(4) +
677 /* IFLA_GRE_IFLAGS */
678 nla_total_size(2) +
679 /* IFLA_GRE_OFLAGS */
680 nla_total_size(2) +
681 /* IFLA_GRE_IKEY */
682 nla_total_size(4) +
683 /* IFLA_GRE_OKEY */
684 nla_total_size(4) +
685 /* IFLA_GRE_LOCAL */
686 nla_total_size(4) +
687 /* IFLA_GRE_REMOTE */
688 nla_total_size(4) +
689 /* IFLA_GRE_TTL */
690 nla_total_size(1) +
691 /* IFLA_GRE_TOS */
692 nla_total_size(1) +
693 /* IFLA_GRE_PMTUDISC */
694 nla_total_size(1) +
695 0;
696}
697
698static int ipgre_fill_info(struct sk_buff *skb, const struct net_device *dev)
699{
700 struct ip_tunnel *t = netdev_priv(dev);
701 struct ip_tunnel_parm *p = &t->parms;
702
David S. Millerf3756b72012-04-01 20:39:02 -0400703 if (nla_put_u32(skb, IFLA_GRE_LINK, p->link) ||
Pravin B Shelarc5441932013-03-25 14:49:35 +0000704 nla_put_be16(skb, IFLA_GRE_IFLAGS, tnl_flags_to_gre_flags(p->i_flags)) ||
705 nla_put_be16(skb, IFLA_GRE_OFLAGS, tnl_flags_to_gre_flags(p->o_flags)) ||
David S. Millerf3756b72012-04-01 20:39:02 -0400706 nla_put_be32(skb, IFLA_GRE_IKEY, p->i_key) ||
707 nla_put_be32(skb, IFLA_GRE_OKEY, p->o_key) ||
708 nla_put_be32(skb, IFLA_GRE_LOCAL, p->iph.saddr) ||
709 nla_put_be32(skb, IFLA_GRE_REMOTE, p->iph.daddr) ||
710 nla_put_u8(skb, IFLA_GRE_TTL, p->iph.ttl) ||
711 nla_put_u8(skb, IFLA_GRE_TOS, p->iph.tos) ||
712 nla_put_u8(skb, IFLA_GRE_PMTUDISC,
713 !!(p->iph.frag_off & htons(IP_DF))))
714 goto nla_put_failure;
Herbert Xuc19e6542008-10-09 11:59:55 -0700715 return 0;
716
717nla_put_failure:
718 return -EMSGSIZE;
719}
720
721static const struct nla_policy ipgre_policy[IFLA_GRE_MAX + 1] = {
722 [IFLA_GRE_LINK] = { .type = NLA_U32 },
723 [IFLA_GRE_IFLAGS] = { .type = NLA_U16 },
724 [IFLA_GRE_OFLAGS] = { .type = NLA_U16 },
725 [IFLA_GRE_IKEY] = { .type = NLA_U32 },
726 [IFLA_GRE_OKEY] = { .type = NLA_U32 },
Patrick McHardy4d74f8b2008-10-10 12:11:06 -0700727 [IFLA_GRE_LOCAL] = { .len = FIELD_SIZEOF(struct iphdr, saddr) },
728 [IFLA_GRE_REMOTE] = { .len = FIELD_SIZEOF(struct iphdr, daddr) },
Herbert Xuc19e6542008-10-09 11:59:55 -0700729 [IFLA_GRE_TTL] = { .type = NLA_U8 },
730 [IFLA_GRE_TOS] = { .type = NLA_U8 },
731 [IFLA_GRE_PMTUDISC] = { .type = NLA_U8 },
732};
733
734static struct rtnl_link_ops ipgre_link_ops __read_mostly = {
735 .kind = "gre",
736 .maxtype = IFLA_GRE_MAX,
737 .policy = ipgre_policy,
738 .priv_size = sizeof(struct ip_tunnel),
739 .setup = ipgre_tunnel_setup,
740 .validate = ipgre_tunnel_validate,
741 .newlink = ipgre_newlink,
742 .changelink = ipgre_changelink,
Pravin B Shelarc5441932013-03-25 14:49:35 +0000743 .dellink = ip_tunnel_dellink,
Herbert Xuc19e6542008-10-09 11:59:55 -0700744 .get_size = ipgre_get_size,
745 .fill_info = ipgre_fill_info,
746};
747
Herbert Xue1a80002008-10-09 12:00:17 -0700748static struct rtnl_link_ops ipgre_tap_ops __read_mostly = {
749 .kind = "gretap",
750 .maxtype = IFLA_GRE_MAX,
751 .policy = ipgre_policy,
752 .priv_size = sizeof(struct ip_tunnel),
753 .setup = ipgre_tap_setup,
754 .validate = ipgre_tap_validate,
755 .newlink = ipgre_newlink,
756 .changelink = ipgre_changelink,
Pravin B Shelarc5441932013-03-25 14:49:35 +0000757 .dellink = ip_tunnel_dellink,
Herbert Xue1a80002008-10-09 12:00:17 -0700758 .get_size = ipgre_get_size,
759 .fill_info = ipgre_fill_info,
760};
761
Pravin B Shelarc5441932013-03-25 14:49:35 +0000762static int __net_init ipgre_tap_init_net(struct net *net)
763{
764 return ip_tunnel_init_net(net, gre_tap_net_id, &ipgre_tap_ops, NULL);
765}
766
767static void __net_exit ipgre_tap_exit_net(struct net *net)
768{
769 struct ip_tunnel_net *itn = net_generic(net, gre_tap_net_id);
Nicolas Dichtel6c742e72013-08-13 17:51:11 +0200770 ip_tunnel_delete_net(itn, &ipgre_tap_ops);
Pravin B Shelarc5441932013-03-25 14:49:35 +0000771}
772
773static struct pernet_operations ipgre_tap_net_ops = {
774 .init = ipgre_tap_init_net,
775 .exit = ipgre_tap_exit_net,
776 .id = &gre_tap_net_id,
777 .size = sizeof(struct ip_tunnel_net),
778};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779
780static int __init ipgre_init(void)
781{
782 int err;
783
Joe Perches058bd4d2012-03-11 18:36:11 +0000784 pr_info("GRE over IPv4 tunneling driver\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785
Eric W. Biedermancfb8fbf2009-11-29 15:46:13 +0000786 err = register_pernet_device(&ipgre_net_ops);
Pavel Emelyanov59a4c752008-04-16 01:08:53 -0700787 if (err < 0)
Alexey Dobriyanc2892f02010-02-16 07:57:44 +0000788 return err;
789
Pravin B Shelarc5441932013-03-25 14:49:35 +0000790 err = register_pernet_device(&ipgre_tap_net_ops);
791 if (err < 0)
792 goto pnet_tap_faied;
793
Pravin B Shelarbda7bb42013-06-17 17:49:38 -0700794 err = gre_cisco_register(&ipgre_protocol);
Alexey Dobriyanc2892f02010-02-16 07:57:44 +0000795 if (err < 0) {
Joe Perches058bd4d2012-03-11 18:36:11 +0000796 pr_info("%s: can't add protocol\n", __func__);
Alexey Dobriyanc2892f02010-02-16 07:57:44 +0000797 goto add_proto_failed;
798 }
Pavel Emelyanov7daa0002008-04-16 01:10:05 -0700799
Herbert Xuc19e6542008-10-09 11:59:55 -0700800 err = rtnl_link_register(&ipgre_link_ops);
801 if (err < 0)
802 goto rtnl_link_failed;
803
Herbert Xue1a80002008-10-09 12:00:17 -0700804 err = rtnl_link_register(&ipgre_tap_ops);
805 if (err < 0)
806 goto tap_ops_failed;
807
Pravin B Shelarc5441932013-03-25 14:49:35 +0000808 return 0;
Herbert Xuc19e6542008-10-09 11:59:55 -0700809
Herbert Xue1a80002008-10-09 12:00:17 -0700810tap_ops_failed:
811 rtnl_link_unregister(&ipgre_link_ops);
Herbert Xuc19e6542008-10-09 11:59:55 -0700812rtnl_link_failed:
Pravin B Shelarbda7bb42013-06-17 17:49:38 -0700813 gre_cisco_unregister(&ipgre_protocol);
Alexey Dobriyanc2892f02010-02-16 07:57:44 +0000814add_proto_failed:
Pravin B Shelarc5441932013-03-25 14:49:35 +0000815 unregister_pernet_device(&ipgre_tap_net_ops);
816pnet_tap_faied:
Alexey Dobriyanc2892f02010-02-16 07:57:44 +0000817 unregister_pernet_device(&ipgre_net_ops);
Pravin B Shelarc5441932013-03-25 14:49:35 +0000818 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819}
820
Alexey Kuznetsovdb445752005-07-30 17:46:44 -0700821static void __exit ipgre_fini(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822{
Herbert Xue1a80002008-10-09 12:00:17 -0700823 rtnl_link_unregister(&ipgre_tap_ops);
Herbert Xuc19e6542008-10-09 11:59:55 -0700824 rtnl_link_unregister(&ipgre_link_ops);
Pravin B Shelarbda7bb42013-06-17 17:49:38 -0700825 gre_cisco_unregister(&ipgre_protocol);
Pravin B Shelarc5441932013-03-25 14:49:35 +0000826 unregister_pernet_device(&ipgre_tap_net_ops);
Alexey Dobriyanc2892f02010-02-16 07:57:44 +0000827 unregister_pernet_device(&ipgre_net_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828}
829
830module_init(ipgre_init);
831module_exit(ipgre_fini);
832MODULE_LICENSE("GPL");
Patrick McHardy4d74f8b2008-10-10 12:11:06 -0700833MODULE_ALIAS_RTNL_LINK("gre");
834MODULE_ALIAS_RTNL_LINK("gretap");
Vasiliy Kulikov8909c9a2011-03-02 00:33:13 +0300835MODULE_ALIAS_NETDEV("gre0");
Pravin B Shelarc5441932013-03-25 14:49:35 +0000836MODULE_ALIAS_NETDEV("gretap0");