xref: /linux/net/ipv4/ip_gre.c (revision 1e99584b911cb6f3d2a681e2532d8dc3f9339c9c)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  *	Linux NET3:	GRE over IP protocol decoder.
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  *	Authors: Alexey Kuznetsov (kuznet@ms2.inr.ac.ru)
51da177e4SLinus Torvalds  *
61da177e4SLinus Torvalds  *	This program is free software; you can redistribute it and/or
71da177e4SLinus Torvalds  *	modify it under the terms of the GNU General Public License
81da177e4SLinus Torvalds  *	as published by the Free Software Foundation; either version
91da177e4SLinus Torvalds  *	2 of the License, or (at your option) any later version.
101da177e4SLinus Torvalds  *
111da177e4SLinus Torvalds  */
121da177e4SLinus Torvalds 
13afd46503SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
14afd46503SJoe Perches 
154fc268d2SRandy Dunlap #include <linux/capability.h>
161da177e4SLinus Torvalds #include <linux/module.h>
171da177e4SLinus Torvalds #include <linux/types.h>
181da177e4SLinus Torvalds #include <linux/kernel.h>
195a0e3ad6STejun Heo #include <linux/slab.h>
201da177e4SLinus Torvalds #include <asm/uaccess.h>
211da177e4SLinus Torvalds #include <linux/skbuff.h>
221da177e4SLinus Torvalds #include <linux/netdevice.h>
231da177e4SLinus Torvalds #include <linux/in.h>
241da177e4SLinus Torvalds #include <linux/tcp.h>
251da177e4SLinus Torvalds #include <linux/udp.h>
261da177e4SLinus Torvalds #include <linux/if_arp.h>
271da177e4SLinus Torvalds #include <linux/mroute.h>
281da177e4SLinus Torvalds #include <linux/init.h>
291da177e4SLinus Torvalds #include <linux/in6.h>
301da177e4SLinus Torvalds #include <linux/inetdevice.h>
311da177e4SLinus Torvalds #include <linux/igmp.h>
321da177e4SLinus Torvalds #include <linux/netfilter_ipv4.h>
33e1a80002SHerbert Xu #include <linux/etherdevice.h>
3446f25dffSKris Katterjohn #include <linux/if_ether.h>
351da177e4SLinus Torvalds 
361da177e4SLinus Torvalds #include <net/sock.h>
371da177e4SLinus Torvalds #include <net/ip.h>
381da177e4SLinus Torvalds #include <net/icmp.h>
391da177e4SLinus Torvalds #include <net/protocol.h>
40c5441932SPravin B Shelar #include <net/ip_tunnels.h>
411da177e4SLinus Torvalds #include <net/arp.h>
421da177e4SLinus Torvalds #include <net/checksum.h>
431da177e4SLinus Torvalds #include <net/dsfield.h>
441da177e4SLinus Torvalds #include <net/inet_ecn.h>
451da177e4SLinus Torvalds #include <net/xfrm.h>
4659a4c759SPavel Emelyanov #include <net/net_namespace.h>
4759a4c759SPavel Emelyanov #include <net/netns/generic.h>
48c19e654dSHerbert Xu #include <net/rtnetlink.h>
4900959adeSDmitry Kozlov #include <net/gre.h>
501da177e4SLinus Torvalds 
51dfd56b8bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6)
521da177e4SLinus Torvalds #include <net/ipv6.h>
531da177e4SLinus Torvalds #include <net/ip6_fib.h>
541da177e4SLinus Torvalds #include <net/ip6_route.h>
551da177e4SLinus Torvalds #endif
561da177e4SLinus Torvalds 
571da177e4SLinus Torvalds /*
581da177e4SLinus Torvalds    Problems & solutions
591da177e4SLinus Torvalds    --------------------
601da177e4SLinus Torvalds 
611da177e4SLinus Torvalds    1. The most important issue is detecting local dead loops.
621da177e4SLinus Torvalds    They would cause complete host lockup in transmit, which
631da177e4SLinus Torvalds    would be "resolved" by stack overflow or, if queueing is enabled,
641da177e4SLinus Torvalds    with infinite looping in net_bh.
651da177e4SLinus Torvalds 
661da177e4SLinus Torvalds    We cannot track such dead loops during route installation,
671da177e4SLinus Torvalds    it is infeasible task. The most general solutions would be
681da177e4SLinus Torvalds    to keep skb->encapsulation counter (sort of local ttl),
696d0722a2SEric Dumazet    and silently drop packet when it expires. It is a good
70bff52857Sstephen hemminger    solution, but it supposes maintaining new variable in ALL
711da177e4SLinus Torvalds    skb, even if no tunneling is used.
721da177e4SLinus Torvalds 
736d0722a2SEric Dumazet    Current solution: xmit_recursion breaks dead loops. This is a percpu
746d0722a2SEric Dumazet    counter, since when we enter the first ndo_xmit(), cpu migration is
756d0722a2SEric Dumazet    forbidden. We force an exit if this counter reaches RECURSION_LIMIT
761da177e4SLinus Torvalds 
771da177e4SLinus Torvalds    2. Networking dead loops would not kill routers, but would really
781da177e4SLinus Torvalds    kill network. IP hop limit plays role of "t->recursion" in this case,
791da177e4SLinus Torvalds    if we copy it from packet being encapsulated to upper header.
801da177e4SLinus Torvalds    It is very good solution, but it introduces two problems:
811da177e4SLinus Torvalds 
821da177e4SLinus Torvalds    - Routing protocols, using packets with ttl=1 (OSPF, RIP2),
831da177e4SLinus Torvalds      do not work over tunnels.
841da177e4SLinus Torvalds    - traceroute does not work. I planned to relay ICMP from tunnel,
851da177e4SLinus Torvalds      so that this problem would be solved and traceroute output
861da177e4SLinus Torvalds      would even more informative. This idea appeared to be wrong:
871da177e4SLinus Torvalds      only Linux complies to rfc1812 now (yes, guys, Linux is the only
881da177e4SLinus Torvalds      true router now :-)), all routers (at least, in neighbourhood of mine)
891da177e4SLinus Torvalds      return only 8 bytes of payload. It is the end.
901da177e4SLinus Torvalds 
911da177e4SLinus Torvalds    Hence, if we want that OSPF worked or traceroute said something reasonable,
921da177e4SLinus Torvalds    we should search for another solution.
931da177e4SLinus Torvalds 
941da177e4SLinus Torvalds    One of them is to parse packet trying to detect inner encapsulation
951da177e4SLinus Torvalds    made by our node. It is difficult or even impossible, especially,
96bff52857Sstephen hemminger    taking into account fragmentation. TO be short, ttl is not solution at all.
971da177e4SLinus Torvalds 
981da177e4SLinus Torvalds    Current solution: The solution was UNEXPECTEDLY SIMPLE.
991da177e4SLinus Torvalds    We force DF flag on tunnels with preconfigured hop limit,
1001da177e4SLinus Torvalds    that is ALL. :-) Well, it does not remove the problem completely,
1011da177e4SLinus Torvalds    but exponential growth of network traffic is changed to linear
1021da177e4SLinus Torvalds    (branches, that exceed pmtu are pruned) and tunnel mtu
103bff52857Sstephen hemminger    rapidly degrades to value <68, where looping stops.
1041da177e4SLinus Torvalds    Yes, it is not good if there exists a router in the loop,
1051da177e4SLinus Torvalds    which does not force DF, even when encapsulating packets have DF set.
1061da177e4SLinus Torvalds    But it is not our problem! Nobody could accuse us, we made
1071da177e4SLinus Torvalds    all that we could make. Even if it is your gated who injected
1081da177e4SLinus Torvalds    fatal route to network, even if it were you who configured
1091da177e4SLinus Torvalds    fatal static route: you are innocent. :-)
1101da177e4SLinus Torvalds 
1111da177e4SLinus Torvalds    Alexey Kuznetsov.
1121da177e4SLinus Torvalds  */
1131da177e4SLinus Torvalds 
114eccc1bb8Sstephen hemminger static bool log_ecn_error = true;
115eccc1bb8Sstephen hemminger module_param(log_ecn_error, bool, 0644);
116eccc1bb8Sstephen hemminger MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN");
117eccc1bb8Sstephen hemminger 
118c19e654dSHerbert Xu static struct rtnl_link_ops ipgre_link_ops __read_mostly;
1191da177e4SLinus Torvalds static int ipgre_tunnel_init(struct net_device *dev);
120eb8ce741SPavel Emelyanov 
121f99189b1SEric Dumazet static int ipgre_net_id __read_mostly;
122c5441932SPravin B Shelar static int gre_tap_net_id __read_mostly;
123eb8ce741SPavel Emelyanov 
124bda7bb46SPravin B Shelar static int ipgre_err(struct sk_buff *skb, u32 info,
125bda7bb46SPravin B Shelar 		     const struct tnl_ptk_info *tpi)
1261da177e4SLinus Torvalds {
1271da177e4SLinus Torvalds 
128071f92d0SRami Rosen 	/* All the routers (except for Linux) return only
1291da177e4SLinus Torvalds 	   8 bytes of packet payload. It means, that precise relaying of
1301da177e4SLinus Torvalds 	   ICMP in the real Internet is absolutely infeasible.
1311da177e4SLinus Torvalds 
1321da177e4SLinus Torvalds 	   Moreover, Cisco "wise men" put GRE key to the third word
133c5441932SPravin B Shelar 	   in GRE header. It makes impossible maintaining even soft
134c5441932SPravin B Shelar 	   state for keyed GRE tunnels with enabled checksum. Tell
135c5441932SPravin B Shelar 	   them "thank you".
1361da177e4SLinus Torvalds 
1371da177e4SLinus Torvalds 	   Well, I wonder, rfc1812 was written by Cisco employee,
138bff52857Sstephen hemminger 	   what the hell these idiots break standards established
139bff52857Sstephen hemminger 	   by themselves???
1401da177e4SLinus Torvalds 	   */
141c5441932SPravin B Shelar 	struct net *net = dev_net(skb->dev);
142c5441932SPravin B Shelar 	struct ip_tunnel_net *itn;
14396f5a846SEric Dumazet 	const struct iphdr *iph;
14488c7664fSArnaldo Carvalho de Melo 	const int type = icmp_hdr(skb)->type;
14588c7664fSArnaldo Carvalho de Melo 	const int code = icmp_hdr(skb)->code;
1461da177e4SLinus Torvalds 	struct ip_tunnel *t;
147d2083287Sstephen hemminger 
1481da177e4SLinus Torvalds 	switch (type) {
1491da177e4SLinus Torvalds 	default:
1501da177e4SLinus Torvalds 	case ICMP_PARAMETERPROB:
151bda7bb46SPravin B Shelar 		return PACKET_RCVD;
1521da177e4SLinus Torvalds 
1531da177e4SLinus Torvalds 	case ICMP_DEST_UNREACH:
1541da177e4SLinus Torvalds 		switch (code) {
1551da177e4SLinus Torvalds 		case ICMP_SR_FAILED:
1561da177e4SLinus Torvalds 		case ICMP_PORT_UNREACH:
1571da177e4SLinus Torvalds 			/* Impossible event. */
158bda7bb46SPravin B Shelar 			return PACKET_RCVD;
1591da177e4SLinus Torvalds 		default:
1601da177e4SLinus Torvalds 			/* All others are translated to HOST_UNREACH.
1611da177e4SLinus Torvalds 			   rfc2003 contains "deep thoughts" about NET_UNREACH,
1621da177e4SLinus Torvalds 			   I believe they are just ether pollution. --ANK
1631da177e4SLinus Torvalds 			 */
1641da177e4SLinus Torvalds 			break;
1651da177e4SLinus Torvalds 		}
1661da177e4SLinus Torvalds 		break;
1671da177e4SLinus Torvalds 	case ICMP_TIME_EXCEEDED:
1681da177e4SLinus Torvalds 		if (code != ICMP_EXC_TTL)
169bda7bb46SPravin B Shelar 			return PACKET_RCVD;
1701da177e4SLinus Torvalds 		break;
17155be7a9cSDavid S. Miller 
17255be7a9cSDavid S. Miller 	case ICMP_REDIRECT:
17355be7a9cSDavid S. Miller 		break;
1741da177e4SLinus Torvalds 	}
1751da177e4SLinus Torvalds 
176bda7bb46SPravin B Shelar 	if (tpi->proto == htons(ETH_P_TEB))
177c5441932SPravin B Shelar 		itn = net_generic(net, gre_tap_net_id);
178c5441932SPravin B Shelar 	else
179c5441932SPravin B Shelar 		itn = net_generic(net, ipgre_net_id);
180c5441932SPravin B Shelar 
181c0c0c50fSDuan Jiong 	iph = (const struct iphdr *)(icmp_hdr(skb) + 1);
182bda7bb46SPravin B Shelar 	t = ip_tunnel_lookup(itn, skb->dev->ifindex, tpi->flags,
183bda7bb46SPravin B Shelar 			     iph->daddr, iph->saddr, tpi->key);
184d2083287Sstephen hemminger 
18536393395SDavid S. Miller 	if (t == NULL)
186bda7bb46SPravin B Shelar 		return PACKET_REJECT;
18736393395SDavid S. Miller 
18836393395SDavid S. Miller 	if (t->parms.iph.daddr == 0 ||
189f97c1e0cSJoe Perches 	    ipv4_is_multicast(t->parms.iph.daddr))
190bda7bb46SPravin B Shelar 		return PACKET_RCVD;
1911da177e4SLinus Torvalds 
1921da177e4SLinus Torvalds 	if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED)
193bda7bb46SPravin B Shelar 		return PACKET_RCVD;
1941da177e4SLinus Torvalds 
195da6185d8SWei Yongjun 	if (time_before(jiffies, t->err_time + IPTUNNEL_ERR_TIMEO))
1961da177e4SLinus Torvalds 		t->err_count++;
1971da177e4SLinus Torvalds 	else
1981da177e4SLinus Torvalds 		t->err_count = 1;
1991da177e4SLinus Torvalds 	t->err_time = jiffies;
200bda7bb46SPravin B Shelar 	return PACKET_RCVD;
2011da177e4SLinus Torvalds }
2021da177e4SLinus Torvalds 
203bda7bb46SPravin B Shelar static int ipgre_rcv(struct sk_buff *skb, const struct tnl_ptk_info *tpi)
2041da177e4SLinus Torvalds {
205c5441932SPravin B Shelar 	struct net *net = dev_net(skb->dev);
206c5441932SPravin B Shelar 	struct ip_tunnel_net *itn;
207b71d1d42SEric Dumazet 	const struct iphdr *iph;
2081da177e4SLinus Torvalds 	struct ip_tunnel *tunnel;
2091da177e4SLinus Torvalds 
210bda7bb46SPravin B Shelar 	if (tpi->proto == htons(ETH_P_TEB))
211c5441932SPravin B Shelar 		itn = net_generic(net, gre_tap_net_id);
212c5441932SPravin B Shelar 	else
213c5441932SPravin B Shelar 		itn = net_generic(net, ipgre_net_id);
214c5441932SPravin B Shelar 
215eddc9ec5SArnaldo Carvalho de Melo 	iph = ip_hdr(skb);
216bda7bb46SPravin B Shelar 	tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, tpi->flags,
217bda7bb46SPravin B Shelar 				  iph->saddr, iph->daddr, tpi->key);
2181da177e4SLinus Torvalds 
219d2083287Sstephen hemminger 	if (tunnel) {
2200e3da5bbSTimo Teräs 		skb_pop_mac_header(skb);
221bda7bb46SPravin B Shelar 		ip_tunnel_rcv(tunnel, skb, tpi, log_ecn_error);
222bda7bb46SPravin B Shelar 		return PACKET_RCVD;
2231da177e4SLinus Torvalds 	}
224bda7bb46SPravin B Shelar 	return PACKET_REJECT;
2251da177e4SLinus Torvalds }
2261da177e4SLinus Torvalds 
227c5441932SPravin B Shelar static void __gre_xmit(struct sk_buff *skb, struct net_device *dev,
228c5441932SPravin B Shelar 		       const struct iphdr *tnl_params,
229c5441932SPravin B Shelar 		       __be16 proto)
230c5441932SPravin B Shelar {
231c5441932SPravin B Shelar 	struct ip_tunnel *tunnel = netdev_priv(dev);
232c5441932SPravin B Shelar 	struct tnl_ptk_info tpi;
233c5441932SPravin B Shelar 
234c5441932SPravin B Shelar 	tpi.flags = tunnel->parms.o_flags;
235c5441932SPravin B Shelar 	tpi.proto = proto;
236c5441932SPravin B Shelar 	tpi.key = tunnel->parms.o_key;
237c5441932SPravin B Shelar 	if (tunnel->parms.o_flags & TUNNEL_SEQ)
238c5441932SPravin B Shelar 		tunnel->o_seqno++;
239c5441932SPravin B Shelar 	tpi.seq = htonl(tunnel->o_seqno);
240cef401deSEric Dumazet 
241c5441932SPravin B Shelar 	/* Push GRE header. */
2424565e991STom Herbert 	gre_build_header(skb, &tpi, tunnel->tun_hlen);
2431da177e4SLinus Torvalds 
24454bc9bacSTom Herbert 	skb_set_inner_protocol(skb, tpi.proto);
24554bc9bacSTom Herbert 
246bf3d6a8fSNicolas Dichtel 	ip_tunnel_xmit(skb, dev, tnl_params, tnl_params->protocol);
2471da177e4SLinus Torvalds }
2481da177e4SLinus Torvalds 
249c5441932SPravin B Shelar static netdev_tx_t ipgre_xmit(struct sk_buff *skb,
250c5441932SPravin B Shelar 			      struct net_device *dev)
251ee34c1ebSMichal Schmidt {
252c5441932SPravin B Shelar 	struct ip_tunnel *tunnel = netdev_priv(dev);
253c5441932SPravin B Shelar 	const struct iphdr *tnl_params;
254ee34c1ebSMichal Schmidt 
255c5441932SPravin B Shelar 	if (dev->header_ops) {
256c5441932SPravin B Shelar 		/* Need space for new headers */
257c5441932SPravin B Shelar 		if (skb_cow_head(skb, dev->needed_headroom -
2582bac7cb3SChen Gang 				      (tunnel->hlen + sizeof(struct iphdr))))
259c5441932SPravin B Shelar 			goto free_skb;
260ee34c1ebSMichal Schmidt 
261c5441932SPravin B Shelar 		tnl_params = (const struct iphdr *)skb->data;
262cbb1e85fSDavid S. Miller 
263c5441932SPravin B Shelar 		/* Pull skb since ip_tunnel_xmit() needs skb->data pointing
264c5441932SPravin B Shelar 		 * to gre header.
265c5441932SPravin B Shelar 		 */
266c5441932SPravin B Shelar 		skb_pull(skb, tunnel->hlen + sizeof(struct iphdr));
2678a0033a9STimo Teräs 		skb_reset_mac_header(skb);
268c5441932SPravin B Shelar 	} else {
269c5441932SPravin B Shelar 		if (skb_cow_head(skb, dev->needed_headroom))
270c5441932SPravin B Shelar 			goto free_skb;
271c5441932SPravin B Shelar 
272c5441932SPravin B Shelar 		tnl_params = &tunnel->parms.iph;
273ee34c1ebSMichal Schmidt 	}
274e1a80002SHerbert Xu 
2758a0033a9STimo Teräs 	skb = gre_handle_offloads(skb, !!(tunnel->parms.o_flags&TUNNEL_CSUM));
2768a0033a9STimo Teräs 	if (IS_ERR(skb))
2778a0033a9STimo Teräs 		goto out;
2788a0033a9STimo Teräs 
279c5441932SPravin B Shelar 	__gre_xmit(skb, dev, tnl_params, skb->protocol);
280c5441932SPravin B Shelar 
281c5441932SPravin B Shelar 	return NETDEV_TX_OK;
282c5441932SPravin B Shelar 
283c5441932SPravin B Shelar free_skb:
2843acfa1e7SEric Dumazet 	kfree_skb(skb);
285c5441932SPravin B Shelar out:
286c5441932SPravin B Shelar 	dev->stats.tx_dropped++;
287c5441932SPravin B Shelar 	return NETDEV_TX_OK;
288ee34c1ebSMichal Schmidt }
289ee34c1ebSMichal Schmidt 
290c5441932SPravin B Shelar static netdev_tx_t gre_tap_xmit(struct sk_buff *skb,
291c5441932SPravin B Shelar 				struct net_device *dev)
292c5441932SPravin B Shelar {
293c5441932SPravin B Shelar 	struct ip_tunnel *tunnel = netdev_priv(dev);
294ee34c1ebSMichal Schmidt 
29545f2e997SPravin B Shelar 	skb = gre_handle_offloads(skb, !!(tunnel->parms.o_flags&TUNNEL_CSUM));
296c5441932SPravin B Shelar 	if (IS_ERR(skb))
297c5441932SPravin B Shelar 		goto out;
298ee34c1ebSMichal Schmidt 
299c5441932SPravin B Shelar 	if (skb_cow_head(skb, dev->needed_headroom))
300c5441932SPravin B Shelar 		goto free_skb;
30142aa9162SHerbert Xu 
302c5441932SPravin B Shelar 	__gre_xmit(skb, dev, &tunnel->parms.iph, htons(ETH_P_TEB));
30342aa9162SHerbert Xu 
304c5441932SPravin B Shelar 	return NETDEV_TX_OK;
305c5441932SPravin B Shelar 
306c5441932SPravin B Shelar free_skb:
3073acfa1e7SEric Dumazet 	kfree_skb(skb);
308c5441932SPravin B Shelar out:
309c5441932SPravin B Shelar 	dev->stats.tx_dropped++;
310c5441932SPravin B Shelar 	return NETDEV_TX_OK;
31168c33163SPravin B Shelar }
312ee34c1ebSMichal Schmidt 
313c5441932SPravin B Shelar static int ipgre_tunnel_ioctl(struct net_device *dev,
314c5441932SPravin B Shelar 			      struct ifreq *ifr, int cmd)
3151da177e4SLinus Torvalds {
3164565e991STom Herbert 	int err;
3171da177e4SLinus Torvalds 	struct ip_tunnel_parm p;
3181da177e4SLinus Torvalds 
3191da177e4SLinus Torvalds 	if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
320c5441932SPravin B Shelar 		return -EFAULT;
3216c734fb8SCong Wang 	if (cmd == SIOCADDTUNNEL || cmd == SIOCCHGTUNNEL) {
3221da177e4SLinus Torvalds 		if (p.iph.version != 4 || p.iph.protocol != IPPROTO_GRE ||
3231da177e4SLinus Torvalds 		    p.iph.ihl != 5 || (p.iph.frag_off&htons(~IP_DF)) ||
3246c734fb8SCong Wang 		    ((p.i_flags|p.o_flags)&(GRE_VERSION|GRE_ROUTING)))
3251da177e4SLinus Torvalds 			return -EINVAL;
326c5441932SPravin B Shelar 	}
327c5441932SPravin B Shelar 	p.i_flags = gre_flags_to_tnl_flags(p.i_flags);
328c5441932SPravin B Shelar 	p.o_flags = gre_flags_to_tnl_flags(p.o_flags);
329c5441932SPravin B Shelar 
330c5441932SPravin B Shelar 	err = ip_tunnel_ioctl(dev, &p, cmd);
331c5441932SPravin B Shelar 	if (err)
332c5441932SPravin B Shelar 		return err;
333c5441932SPravin B Shelar 
334c5441932SPravin B Shelar 	p.i_flags = tnl_flags_to_gre_flags(p.i_flags);
335c5441932SPravin B Shelar 	p.o_flags = tnl_flags_to_gre_flags(p.o_flags);
336c5441932SPravin B Shelar 
337c5441932SPravin B Shelar 	if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p)))
338c5441932SPravin B Shelar 		return -EFAULT;
3391da177e4SLinus Torvalds 	return 0;
3401da177e4SLinus Torvalds }
3411da177e4SLinus Torvalds 
3421da177e4SLinus Torvalds /* Nice toy. Unfortunately, useless in real life :-)
3431da177e4SLinus Torvalds    It allows to construct virtual multiprotocol broadcast "LAN"
3441da177e4SLinus Torvalds    over the Internet, provided multicast routing is tuned.
3451da177e4SLinus Torvalds 
3461da177e4SLinus Torvalds 
3471da177e4SLinus Torvalds    I have no idea was this bicycle invented before me,
3481da177e4SLinus Torvalds    so that I had to set ARPHRD_IPGRE to a random value.
3491da177e4SLinus Torvalds    I have an impression, that Cisco could make something similar,
3501da177e4SLinus Torvalds    but this feature is apparently missing in IOS<=11.2(8).
3511da177e4SLinus Torvalds 
3521da177e4SLinus Torvalds    I set up 10.66.66/24 and fec0:6666:6666::0/96 as virtual networks
3531da177e4SLinus Torvalds    with broadcast 224.66.66.66. If you have access to mbone, play with me :-)
3541da177e4SLinus Torvalds 
3551da177e4SLinus Torvalds    ping -t 255 224.66.66.66
3561da177e4SLinus Torvalds 
3571da177e4SLinus Torvalds    If nobody answers, mbone does not work.
3581da177e4SLinus Torvalds 
3591da177e4SLinus Torvalds    ip tunnel add Universe mode gre remote 224.66.66.66 local <Your_real_addr> ttl 255
3601da177e4SLinus Torvalds    ip addr add 10.66.66.<somewhat>/24 dev Universe
3611da177e4SLinus Torvalds    ifconfig Universe up
3621da177e4SLinus Torvalds    ifconfig Universe add fe80::<Your_real_addr>/10
3631da177e4SLinus Torvalds    ifconfig Universe add fec0:6666:6666::<Your_real_addr>/96
3641da177e4SLinus Torvalds    ftp 10.66.66.66
3651da177e4SLinus Torvalds    ...
3661da177e4SLinus Torvalds    ftp fec0:6666:6666::193.233.7.65
3671da177e4SLinus Torvalds    ...
3681da177e4SLinus Torvalds  */
3693b04dddeSStephen Hemminger static int ipgre_header(struct sk_buff *skb, struct net_device *dev,
3703b04dddeSStephen Hemminger 			unsigned short type,
3711507850bSEric Dumazet 			const void *daddr, const void *saddr, unsigned int len)
3721da177e4SLinus Torvalds {
3732941a486SPatrick McHardy 	struct ip_tunnel *t = netdev_priv(dev);
374c5441932SPravin B Shelar 	struct iphdr *iph;
375c5441932SPravin B Shelar 	struct gre_base_hdr *greh;
376c5441932SPravin B Shelar 
377c5441932SPravin B Shelar 	iph = (struct iphdr *)skb_push(skb, t->hlen + sizeof(*iph));
378c5441932SPravin B Shelar 	greh = (struct gre_base_hdr *)(iph+1);
379c5441932SPravin B Shelar 	greh->flags = tnl_flags_to_gre_flags(t->parms.o_flags);
380c5441932SPravin B Shelar 	greh->protocol = htons(type);
3811da177e4SLinus Torvalds 
3821da177e4SLinus Torvalds 	memcpy(iph, &t->parms.iph, sizeof(struct iphdr));
3831da177e4SLinus Torvalds 
384c5441932SPravin B Shelar 	/* Set the source hardware address. */
3851da177e4SLinus Torvalds 	if (saddr)
3861da177e4SLinus Torvalds 		memcpy(&iph->saddr, saddr, 4);
3876d55cb91STimo Teräs 	if (daddr)
3881da177e4SLinus Torvalds 		memcpy(&iph->daddr, daddr, 4);
3896d55cb91STimo Teräs 	if (iph->daddr)
39077a482bdSTimo Teräs 		return t->hlen + sizeof(*iph);
3911da177e4SLinus Torvalds 
392c5441932SPravin B Shelar 	return -(t->hlen + sizeof(*iph));
3931da177e4SLinus Torvalds }
3941da177e4SLinus Torvalds 
3956a5f44d7STimo Teras static int ipgre_header_parse(const struct sk_buff *skb, unsigned char *haddr)
3966a5f44d7STimo Teras {
397b71d1d42SEric Dumazet 	const struct iphdr *iph = (const struct iphdr *) skb_mac_header(skb);
3986a5f44d7STimo Teras 	memcpy(haddr, &iph->saddr, 4);
3996a5f44d7STimo Teras 	return 4;
4006a5f44d7STimo Teras }
4016a5f44d7STimo Teras 
4023b04dddeSStephen Hemminger static const struct header_ops ipgre_header_ops = {
4033b04dddeSStephen Hemminger 	.create	= ipgre_header,
4046a5f44d7STimo Teras 	.parse	= ipgre_header_parse,
4053b04dddeSStephen Hemminger };
4063b04dddeSStephen Hemminger 
4076a5f44d7STimo Teras #ifdef CONFIG_NET_IPGRE_BROADCAST
4081da177e4SLinus Torvalds static int ipgre_open(struct net_device *dev)
4091da177e4SLinus Torvalds {
4102941a486SPatrick McHardy 	struct ip_tunnel *t = netdev_priv(dev);
4111da177e4SLinus Torvalds 
412f97c1e0cSJoe Perches 	if (ipv4_is_multicast(t->parms.iph.daddr)) {
413cbb1e85fSDavid S. Miller 		struct flowi4 fl4;
414cbb1e85fSDavid S. Miller 		struct rtable *rt;
415cbb1e85fSDavid S. Miller 
416b57708adSNicolas Dichtel 		rt = ip_route_output_gre(t->net, &fl4,
41778fbfd8aSDavid S. Miller 					 t->parms.iph.daddr,
41878fbfd8aSDavid S. Miller 					 t->parms.iph.saddr,
41978fbfd8aSDavid S. Miller 					 t->parms.o_key,
42078fbfd8aSDavid S. Miller 					 RT_TOS(t->parms.iph.tos),
42178fbfd8aSDavid S. Miller 					 t->parms.link);
422b23dd4feSDavid S. Miller 		if (IS_ERR(rt))
4231da177e4SLinus Torvalds 			return -EADDRNOTAVAIL;
424d8d1f30bSChangli Gao 		dev = rt->dst.dev;
4251da177e4SLinus Torvalds 		ip_rt_put(rt);
426e5ed6399SHerbert Xu 		if (__in_dev_get_rtnl(dev) == NULL)
4271da177e4SLinus Torvalds 			return -EADDRNOTAVAIL;
4281da177e4SLinus Torvalds 		t->mlink = dev->ifindex;
429e5ed6399SHerbert Xu 		ip_mc_inc_group(__in_dev_get_rtnl(dev), t->parms.iph.daddr);
4301da177e4SLinus Torvalds 	}
4311da177e4SLinus Torvalds 	return 0;
4321da177e4SLinus Torvalds }
4331da177e4SLinus Torvalds 
4341da177e4SLinus Torvalds static int ipgre_close(struct net_device *dev)
4351da177e4SLinus Torvalds {
4362941a486SPatrick McHardy 	struct ip_tunnel *t = netdev_priv(dev);
437b8c26a33SStephen Hemminger 
438f97c1e0cSJoe Perches 	if (ipv4_is_multicast(t->parms.iph.daddr) && t->mlink) {
4397fee0ca2SDenis V. Lunev 		struct in_device *in_dev;
440b57708adSNicolas Dichtel 		in_dev = inetdev_by_index(t->net, t->mlink);
4418723e1b4SEric Dumazet 		if (in_dev)
4421da177e4SLinus Torvalds 			ip_mc_dec_group(in_dev, t->parms.iph.daddr);
4431da177e4SLinus Torvalds 	}
4441da177e4SLinus Torvalds 	return 0;
4451da177e4SLinus Torvalds }
4461da177e4SLinus Torvalds #endif
4471da177e4SLinus Torvalds 
448b8c26a33SStephen Hemminger static const struct net_device_ops ipgre_netdev_ops = {
449b8c26a33SStephen Hemminger 	.ndo_init		= ipgre_tunnel_init,
450c5441932SPravin B Shelar 	.ndo_uninit		= ip_tunnel_uninit,
451b8c26a33SStephen Hemminger #ifdef CONFIG_NET_IPGRE_BROADCAST
452b8c26a33SStephen Hemminger 	.ndo_open		= ipgre_open,
453b8c26a33SStephen Hemminger 	.ndo_stop		= ipgre_close,
454b8c26a33SStephen Hemminger #endif
455c5441932SPravin B Shelar 	.ndo_start_xmit		= ipgre_xmit,
456b8c26a33SStephen Hemminger 	.ndo_do_ioctl		= ipgre_tunnel_ioctl,
457c5441932SPravin B Shelar 	.ndo_change_mtu		= ip_tunnel_change_mtu,
458c5441932SPravin B Shelar 	.ndo_get_stats64	= ip_tunnel_get_stats64,
459*1e99584bSNicolas Dichtel 	.ndo_get_iflink		= ip_tunnel_get_iflink,
460b8c26a33SStephen Hemminger };
461b8c26a33SStephen Hemminger 
4626b78f16eSEric Dumazet #define GRE_FEATURES (NETIF_F_SG |		\
4636b78f16eSEric Dumazet 		      NETIF_F_FRAGLIST |	\
4646b78f16eSEric Dumazet 		      NETIF_F_HIGHDMA |		\
4656b78f16eSEric Dumazet 		      NETIF_F_HW_CSUM)
4666b78f16eSEric Dumazet 
4671da177e4SLinus Torvalds static void ipgre_tunnel_setup(struct net_device *dev)
4681da177e4SLinus Torvalds {
469b8c26a33SStephen Hemminger 	dev->netdev_ops		= &ipgre_netdev_ops;
4705a455275SNicolas Dichtel 	dev->type		= ARPHRD_IPGRE;
471c5441932SPravin B Shelar 	ip_tunnel_setup(dev, ipgre_net_id);
472c5441932SPravin B Shelar }
4731da177e4SLinus Torvalds 
474c5441932SPravin B Shelar static void __gre_tunnel_init(struct net_device *dev)
475c5441932SPravin B Shelar {
476c5441932SPravin B Shelar 	struct ip_tunnel *tunnel;
4774565e991STom Herbert 	int t_hlen;
478c5441932SPravin B Shelar 
479c5441932SPravin B Shelar 	tunnel = netdev_priv(dev);
4804565e991STom Herbert 	tunnel->tun_hlen = ip_gre_calc_hlen(tunnel->parms.o_flags);
481c5441932SPravin B Shelar 	tunnel->parms.iph.protocol = IPPROTO_GRE;
482c5441932SPravin B Shelar 
4834565e991STom Herbert 	tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen;
4844565e991STom Herbert 
4854565e991STom Herbert 	t_hlen = tunnel->hlen + sizeof(struct iphdr);
4864565e991STom Herbert 
4874565e991STom Herbert 	dev->needed_headroom	= LL_MAX_HEADER + t_hlen + 4;
4884565e991STom Herbert 	dev->mtu		= ETH_DATA_LEN - t_hlen - 4;
4896b78f16eSEric Dumazet 
490b57708adSNicolas Dichtel 	dev->features		|= GRE_FEATURES;
4916b78f16eSEric Dumazet 	dev->hw_features	|= GRE_FEATURES;
492c5441932SPravin B Shelar 
493c5441932SPravin B Shelar 	if (!(tunnel->parms.o_flags & TUNNEL_SEQ)) {
494c5441932SPravin B Shelar 		/* TCP offload with GRE SEQ is not supported. */
495c5441932SPravin B Shelar 		dev->features    |= NETIF_F_GSO_SOFTWARE;
496c5441932SPravin B Shelar 		dev->hw_features |= NETIF_F_GSO_SOFTWARE;
497c5441932SPravin B Shelar 		/* Can use a lockless transmit, unless we generate
498c5441932SPravin B Shelar 		 * output sequences
499c5441932SPravin B Shelar 		 */
500c5441932SPravin B Shelar 		dev->features |= NETIF_F_LLTX;
501c5441932SPravin B Shelar 	}
5021da177e4SLinus Torvalds }
5031da177e4SLinus Torvalds 
5041da177e4SLinus Torvalds static int ipgre_tunnel_init(struct net_device *dev)
5051da177e4SLinus Torvalds {
506c5441932SPravin B Shelar 	struct ip_tunnel *tunnel = netdev_priv(dev);
507c5441932SPravin B Shelar 	struct iphdr *iph = &tunnel->parms.iph;
5081da177e4SLinus Torvalds 
509c5441932SPravin B Shelar 	__gre_tunnel_init(dev);
5101da177e4SLinus Torvalds 
511c5441932SPravin B Shelar 	memcpy(dev->dev_addr, &iph->saddr, 4);
512c5441932SPravin B Shelar 	memcpy(dev->broadcast, &iph->daddr, 4);
5131da177e4SLinus Torvalds 
514c5441932SPravin B Shelar 	dev->flags		= IFF_NOARP;
51502875878SEric Dumazet 	netif_keep_dst(dev);
516c5441932SPravin B Shelar 	dev->addr_len		= 4;
5171da177e4SLinus Torvalds 
5181da177e4SLinus Torvalds 	if (iph->daddr) {
5191da177e4SLinus Torvalds #ifdef CONFIG_NET_IPGRE_BROADCAST
520f97c1e0cSJoe Perches 		if (ipv4_is_multicast(iph->daddr)) {
5211da177e4SLinus Torvalds 			if (!iph->saddr)
5221da177e4SLinus Torvalds 				return -EINVAL;
5231da177e4SLinus Torvalds 			dev->flags = IFF_BROADCAST;
5243b04dddeSStephen Hemminger 			dev->header_ops = &ipgre_header_ops;
5251da177e4SLinus Torvalds 		}
5261da177e4SLinus Torvalds #endif
527ee34c1ebSMichal Schmidt 	} else
5286a5f44d7STimo Teras 		dev->header_ops = &ipgre_header_ops;
5291da177e4SLinus Torvalds 
530c5441932SPravin B Shelar 	return ip_tunnel_init(dev);
53160769a5dSEric Dumazet }
53260769a5dSEric Dumazet 
533bda7bb46SPravin B Shelar static struct gre_cisco_protocol ipgre_protocol = {
5341da177e4SLinus Torvalds 	.handler        = ipgre_rcv,
5351da177e4SLinus Torvalds 	.err_handler    = ipgre_err,
536bda7bb46SPravin B Shelar 	.priority       = 0,
5371da177e4SLinus Torvalds };
5381da177e4SLinus Torvalds 
5392c8c1e72SAlexey Dobriyan static int __net_init ipgre_init_net(struct net *net)
54059a4c759SPavel Emelyanov {
541c5441932SPravin B Shelar 	return ip_tunnel_init_net(net, ipgre_net_id, &ipgre_link_ops, NULL);
54259a4c759SPavel Emelyanov }
54359a4c759SPavel Emelyanov 
5442c8c1e72SAlexey Dobriyan static void __net_exit ipgre_exit_net(struct net *net)
54559a4c759SPavel Emelyanov {
546c5441932SPravin B Shelar 	struct ip_tunnel_net *itn = net_generic(net, ipgre_net_id);
5476c742e71SNicolas Dichtel 	ip_tunnel_delete_net(itn, &ipgre_link_ops);
54859a4c759SPavel Emelyanov }
54959a4c759SPavel Emelyanov 
55059a4c759SPavel Emelyanov static struct pernet_operations ipgre_net_ops = {
55159a4c759SPavel Emelyanov 	.init = ipgre_init_net,
55259a4c759SPavel Emelyanov 	.exit = ipgre_exit_net,
553cfb8fbf2SEric W. Biederman 	.id   = &ipgre_net_id,
554c5441932SPravin B Shelar 	.size = sizeof(struct ip_tunnel_net),
55559a4c759SPavel Emelyanov };
5561da177e4SLinus Torvalds 
557c19e654dSHerbert Xu static int ipgre_tunnel_validate(struct nlattr *tb[], struct nlattr *data[])
558c19e654dSHerbert Xu {
559c19e654dSHerbert Xu 	__be16 flags;
560c19e654dSHerbert Xu 
561c19e654dSHerbert Xu 	if (!data)
562c19e654dSHerbert Xu 		return 0;
563c19e654dSHerbert Xu 
564c19e654dSHerbert Xu 	flags = 0;
565c19e654dSHerbert Xu 	if (data[IFLA_GRE_IFLAGS])
566c19e654dSHerbert Xu 		flags |= nla_get_be16(data[IFLA_GRE_IFLAGS]);
567c19e654dSHerbert Xu 	if (data[IFLA_GRE_OFLAGS])
568c19e654dSHerbert Xu 		flags |= nla_get_be16(data[IFLA_GRE_OFLAGS]);
569c19e654dSHerbert Xu 	if (flags & (GRE_VERSION|GRE_ROUTING))
570c19e654dSHerbert Xu 		return -EINVAL;
571c19e654dSHerbert Xu 
572c19e654dSHerbert Xu 	return 0;
573c19e654dSHerbert Xu }
574c19e654dSHerbert Xu 
575e1a80002SHerbert Xu static int ipgre_tap_validate(struct nlattr *tb[], struct nlattr *data[])
576e1a80002SHerbert Xu {
577e1a80002SHerbert Xu 	__be32 daddr;
578e1a80002SHerbert Xu 
579e1a80002SHerbert Xu 	if (tb[IFLA_ADDRESS]) {
580e1a80002SHerbert Xu 		if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN)
581e1a80002SHerbert Xu 			return -EINVAL;
582e1a80002SHerbert Xu 		if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS])))
583e1a80002SHerbert Xu 			return -EADDRNOTAVAIL;
584e1a80002SHerbert Xu 	}
585e1a80002SHerbert Xu 
586e1a80002SHerbert Xu 	if (!data)
587e1a80002SHerbert Xu 		goto out;
588e1a80002SHerbert Xu 
589e1a80002SHerbert Xu 	if (data[IFLA_GRE_REMOTE]) {
590e1a80002SHerbert Xu 		memcpy(&daddr, nla_data(data[IFLA_GRE_REMOTE]), 4);
591e1a80002SHerbert Xu 		if (!daddr)
592e1a80002SHerbert Xu 			return -EINVAL;
593e1a80002SHerbert Xu 	}
594e1a80002SHerbert Xu 
595e1a80002SHerbert Xu out:
596e1a80002SHerbert Xu 	return ipgre_tunnel_validate(tb, data);
597e1a80002SHerbert Xu }
598e1a80002SHerbert Xu 
599c5441932SPravin B Shelar static void ipgre_netlink_parms(struct nlattr *data[], struct nlattr *tb[],
600c19e654dSHerbert Xu 			       struct ip_tunnel_parm *parms)
601c19e654dSHerbert Xu {
6027bb82d92SHerbert Xu 	memset(parms, 0, sizeof(*parms));
603c19e654dSHerbert Xu 
604c19e654dSHerbert Xu 	parms->iph.protocol = IPPROTO_GRE;
605c19e654dSHerbert Xu 
606c19e654dSHerbert Xu 	if (!data)
607c19e654dSHerbert Xu 		return;
608c19e654dSHerbert Xu 
609c19e654dSHerbert Xu 	if (data[IFLA_GRE_LINK])
610c19e654dSHerbert Xu 		parms->link = nla_get_u32(data[IFLA_GRE_LINK]);
611c19e654dSHerbert Xu 
612c19e654dSHerbert Xu 	if (data[IFLA_GRE_IFLAGS])
613c5441932SPravin B Shelar 		parms->i_flags = gre_flags_to_tnl_flags(nla_get_be16(data[IFLA_GRE_IFLAGS]));
614c19e654dSHerbert Xu 
615c19e654dSHerbert Xu 	if (data[IFLA_GRE_OFLAGS])
616c5441932SPravin B Shelar 		parms->o_flags = gre_flags_to_tnl_flags(nla_get_be16(data[IFLA_GRE_OFLAGS]));
617c19e654dSHerbert Xu 
618c19e654dSHerbert Xu 	if (data[IFLA_GRE_IKEY])
619c19e654dSHerbert Xu 		parms->i_key = nla_get_be32(data[IFLA_GRE_IKEY]);
620c19e654dSHerbert Xu 
621c19e654dSHerbert Xu 	if (data[IFLA_GRE_OKEY])
622c19e654dSHerbert Xu 		parms->o_key = nla_get_be32(data[IFLA_GRE_OKEY]);
623c19e654dSHerbert Xu 
624c19e654dSHerbert Xu 	if (data[IFLA_GRE_LOCAL])
62567b61f6cSJiri Benc 		parms->iph.saddr = nla_get_in_addr(data[IFLA_GRE_LOCAL]);
626c19e654dSHerbert Xu 
627c19e654dSHerbert Xu 	if (data[IFLA_GRE_REMOTE])
62867b61f6cSJiri Benc 		parms->iph.daddr = nla_get_in_addr(data[IFLA_GRE_REMOTE]);
629c19e654dSHerbert Xu 
630c19e654dSHerbert Xu 	if (data[IFLA_GRE_TTL])
631c19e654dSHerbert Xu 		parms->iph.ttl = nla_get_u8(data[IFLA_GRE_TTL]);
632c19e654dSHerbert Xu 
633c19e654dSHerbert Xu 	if (data[IFLA_GRE_TOS])
634c19e654dSHerbert Xu 		parms->iph.tos = nla_get_u8(data[IFLA_GRE_TOS]);
635c19e654dSHerbert Xu 
636c19e654dSHerbert Xu 	if (!data[IFLA_GRE_PMTUDISC] || nla_get_u8(data[IFLA_GRE_PMTUDISC]))
637c19e654dSHerbert Xu 		parms->iph.frag_off = htons(IP_DF);
638c19e654dSHerbert Xu }
639c19e654dSHerbert Xu 
6404565e991STom Herbert /* This function returns true when ENCAP attributes are present in the nl msg */
6414565e991STom Herbert static bool ipgre_netlink_encap_parms(struct nlattr *data[],
6424565e991STom Herbert 				      struct ip_tunnel_encap *ipencap)
6434565e991STom Herbert {
6444565e991STom Herbert 	bool ret = false;
6454565e991STom Herbert 
6464565e991STom Herbert 	memset(ipencap, 0, sizeof(*ipencap));
6474565e991STom Herbert 
6484565e991STom Herbert 	if (!data)
6494565e991STom Herbert 		return ret;
6504565e991STom Herbert 
6514565e991STom Herbert 	if (data[IFLA_GRE_ENCAP_TYPE]) {
6524565e991STom Herbert 		ret = true;
6534565e991STom Herbert 		ipencap->type = nla_get_u16(data[IFLA_GRE_ENCAP_TYPE]);
6544565e991STom Herbert 	}
6554565e991STom Herbert 
6564565e991STom Herbert 	if (data[IFLA_GRE_ENCAP_FLAGS]) {
6574565e991STom Herbert 		ret = true;
6584565e991STom Herbert 		ipencap->flags = nla_get_u16(data[IFLA_GRE_ENCAP_FLAGS]);
6594565e991STom Herbert 	}
6604565e991STom Herbert 
6614565e991STom Herbert 	if (data[IFLA_GRE_ENCAP_SPORT]) {
6624565e991STom Herbert 		ret = true;
6633e97fa70SSabrina Dubroca 		ipencap->sport = nla_get_be16(data[IFLA_GRE_ENCAP_SPORT]);
6644565e991STom Herbert 	}
6654565e991STom Herbert 
6664565e991STom Herbert 	if (data[IFLA_GRE_ENCAP_DPORT]) {
6674565e991STom Herbert 		ret = true;
6683e97fa70SSabrina Dubroca 		ipencap->dport = nla_get_be16(data[IFLA_GRE_ENCAP_DPORT]);
6694565e991STom Herbert 	}
6704565e991STom Herbert 
6714565e991STom Herbert 	return ret;
6724565e991STom Herbert }
6734565e991STom Herbert 
674c5441932SPravin B Shelar static int gre_tap_init(struct net_device *dev)
675e1a80002SHerbert Xu {
676c5441932SPravin B Shelar 	__gre_tunnel_init(dev);
677bec94d43Sstephen hemminger 	dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
678e1a80002SHerbert Xu 
679c5441932SPravin B Shelar 	return ip_tunnel_init(dev);
680e1a80002SHerbert Xu }
681e1a80002SHerbert Xu 
682c5441932SPravin B Shelar static const struct net_device_ops gre_tap_netdev_ops = {
683c5441932SPravin B Shelar 	.ndo_init		= gre_tap_init,
684c5441932SPravin B Shelar 	.ndo_uninit		= ip_tunnel_uninit,
685c5441932SPravin B Shelar 	.ndo_start_xmit		= gre_tap_xmit,
686b8c26a33SStephen Hemminger 	.ndo_set_mac_address 	= eth_mac_addr,
687b8c26a33SStephen Hemminger 	.ndo_validate_addr	= eth_validate_addr,
688c5441932SPravin B Shelar 	.ndo_change_mtu		= ip_tunnel_change_mtu,
689c5441932SPravin B Shelar 	.ndo_get_stats64	= ip_tunnel_get_stats64,
690*1e99584bSNicolas Dichtel 	.ndo_get_iflink		= ip_tunnel_get_iflink,
691b8c26a33SStephen Hemminger };
692b8c26a33SStephen Hemminger 
693e1a80002SHerbert Xu static void ipgre_tap_setup(struct net_device *dev)
694e1a80002SHerbert Xu {
695e1a80002SHerbert Xu 	ether_setup(dev);
696c5441932SPravin B Shelar 	dev->netdev_ops		= &gre_tap_netdev_ops;
697f8c1b7ceSstephen hemminger 	dev->priv_flags 	|= IFF_LIVE_ADDR_CHANGE;
698c5441932SPravin B Shelar 	ip_tunnel_setup(dev, gre_tap_net_id);
699e1a80002SHerbert Xu }
700e1a80002SHerbert Xu 
701c5441932SPravin B Shelar static int ipgre_newlink(struct net *src_net, struct net_device *dev,
702c5441932SPravin B Shelar 			 struct nlattr *tb[], struct nlattr *data[])
703c19e654dSHerbert Xu {
704c5441932SPravin B Shelar 	struct ip_tunnel_parm p;
7054565e991STom Herbert 	struct ip_tunnel_encap ipencap;
7064565e991STom Herbert 
7074565e991STom Herbert 	if (ipgre_netlink_encap_parms(data, &ipencap)) {
7084565e991STom Herbert 		struct ip_tunnel *t = netdev_priv(dev);
7094565e991STom Herbert 		int err = ip_tunnel_encap_setup(t, &ipencap);
7104565e991STom Herbert 
7114565e991STom Herbert 		if (err < 0)
7124565e991STom Herbert 			return err;
7134565e991STom Herbert 	}
714c19e654dSHerbert Xu 
715c5441932SPravin B Shelar 	ipgre_netlink_parms(data, tb, &p);
716c5441932SPravin B Shelar 	return ip_tunnel_newlink(dev, tb, &p);
717c19e654dSHerbert Xu }
718c19e654dSHerbert Xu 
719c19e654dSHerbert Xu static int ipgre_changelink(struct net_device *dev, struct nlattr *tb[],
720c19e654dSHerbert Xu 			    struct nlattr *data[])
721c19e654dSHerbert Xu {
722c19e654dSHerbert Xu 	struct ip_tunnel_parm p;
7234565e991STom Herbert 	struct ip_tunnel_encap ipencap;
7244565e991STom Herbert 
7254565e991STom Herbert 	if (ipgre_netlink_encap_parms(data, &ipencap)) {
7264565e991STom Herbert 		struct ip_tunnel *t = netdev_priv(dev);
7274565e991STom Herbert 		int err = ip_tunnel_encap_setup(t, &ipencap);
7284565e991STom Herbert 
7294565e991STom Herbert 		if (err < 0)
7304565e991STom Herbert 			return err;
7314565e991STom Herbert 	}
732c19e654dSHerbert Xu 
733c5441932SPravin B Shelar 	ipgre_netlink_parms(data, tb, &p);
734c5441932SPravin B Shelar 	return ip_tunnel_changelink(dev, tb, &p);
735c19e654dSHerbert Xu }
736c19e654dSHerbert Xu 
737c19e654dSHerbert Xu static size_t ipgre_get_size(const struct net_device *dev)
738c19e654dSHerbert Xu {
739c19e654dSHerbert Xu 	return
740c19e654dSHerbert Xu 		/* IFLA_GRE_LINK */
741c19e654dSHerbert Xu 		nla_total_size(4) +
742c19e654dSHerbert Xu 		/* IFLA_GRE_IFLAGS */
743c19e654dSHerbert Xu 		nla_total_size(2) +
744c19e654dSHerbert Xu 		/* IFLA_GRE_OFLAGS */
745c19e654dSHerbert Xu 		nla_total_size(2) +
746c19e654dSHerbert Xu 		/* IFLA_GRE_IKEY */
747c19e654dSHerbert Xu 		nla_total_size(4) +
748c19e654dSHerbert Xu 		/* IFLA_GRE_OKEY */
749c19e654dSHerbert Xu 		nla_total_size(4) +
750c19e654dSHerbert Xu 		/* IFLA_GRE_LOCAL */
751c19e654dSHerbert Xu 		nla_total_size(4) +
752c19e654dSHerbert Xu 		/* IFLA_GRE_REMOTE */
753c19e654dSHerbert Xu 		nla_total_size(4) +
754c19e654dSHerbert Xu 		/* IFLA_GRE_TTL */
755c19e654dSHerbert Xu 		nla_total_size(1) +
756c19e654dSHerbert Xu 		/* IFLA_GRE_TOS */
757c19e654dSHerbert Xu 		nla_total_size(1) +
758c19e654dSHerbert Xu 		/* IFLA_GRE_PMTUDISC */
759c19e654dSHerbert Xu 		nla_total_size(1) +
7604565e991STom Herbert 		/* IFLA_GRE_ENCAP_TYPE */
7614565e991STom Herbert 		nla_total_size(2) +
7624565e991STom Herbert 		/* IFLA_GRE_ENCAP_FLAGS */
7634565e991STom Herbert 		nla_total_size(2) +
7644565e991STom Herbert 		/* IFLA_GRE_ENCAP_SPORT */
7654565e991STom Herbert 		nla_total_size(2) +
7664565e991STom Herbert 		/* IFLA_GRE_ENCAP_DPORT */
7674565e991STom Herbert 		nla_total_size(2) +
768c19e654dSHerbert Xu 		0;
769c19e654dSHerbert Xu }
770c19e654dSHerbert Xu 
771c19e654dSHerbert Xu static int ipgre_fill_info(struct sk_buff *skb, const struct net_device *dev)
772c19e654dSHerbert Xu {
773c19e654dSHerbert Xu 	struct ip_tunnel *t = netdev_priv(dev);
774c19e654dSHerbert Xu 	struct ip_tunnel_parm *p = &t->parms;
775c19e654dSHerbert Xu 
776f3756b79SDavid S. Miller 	if (nla_put_u32(skb, IFLA_GRE_LINK, p->link) ||
777c5441932SPravin B Shelar 	    nla_put_be16(skb, IFLA_GRE_IFLAGS, tnl_flags_to_gre_flags(p->i_flags)) ||
778c5441932SPravin B Shelar 	    nla_put_be16(skb, IFLA_GRE_OFLAGS, tnl_flags_to_gre_flags(p->o_flags)) ||
779f3756b79SDavid S. Miller 	    nla_put_be32(skb, IFLA_GRE_IKEY, p->i_key) ||
780f3756b79SDavid S. Miller 	    nla_put_be32(skb, IFLA_GRE_OKEY, p->o_key) ||
781930345eaSJiri Benc 	    nla_put_in_addr(skb, IFLA_GRE_LOCAL, p->iph.saddr) ||
782930345eaSJiri Benc 	    nla_put_in_addr(skb, IFLA_GRE_REMOTE, p->iph.daddr) ||
783f3756b79SDavid S. Miller 	    nla_put_u8(skb, IFLA_GRE_TTL, p->iph.ttl) ||
784f3756b79SDavid S. Miller 	    nla_put_u8(skb, IFLA_GRE_TOS, p->iph.tos) ||
785f3756b79SDavid S. Miller 	    nla_put_u8(skb, IFLA_GRE_PMTUDISC,
786f3756b79SDavid S. Miller 		       !!(p->iph.frag_off & htons(IP_DF))))
787f3756b79SDavid S. Miller 		goto nla_put_failure;
7884565e991STom Herbert 
7894565e991STom Herbert 	if (nla_put_u16(skb, IFLA_GRE_ENCAP_TYPE,
7904565e991STom Herbert 			t->encap.type) ||
7913e97fa70SSabrina Dubroca 	    nla_put_be16(skb, IFLA_GRE_ENCAP_SPORT,
7924565e991STom Herbert 			 t->encap.sport) ||
7933e97fa70SSabrina Dubroca 	    nla_put_be16(skb, IFLA_GRE_ENCAP_DPORT,
7944565e991STom Herbert 			 t->encap.dport) ||
7954565e991STom Herbert 	    nla_put_u16(skb, IFLA_GRE_ENCAP_FLAGS,
796e1b2cb65STom Herbert 			t->encap.flags))
7974565e991STom Herbert 		goto nla_put_failure;
7984565e991STom Herbert 
799c19e654dSHerbert Xu 	return 0;
800c19e654dSHerbert Xu 
801c19e654dSHerbert Xu nla_put_failure:
802c19e654dSHerbert Xu 	return -EMSGSIZE;
803c19e654dSHerbert Xu }
804c19e654dSHerbert Xu 
805c19e654dSHerbert Xu static const struct nla_policy ipgre_policy[IFLA_GRE_MAX + 1] = {
806c19e654dSHerbert Xu 	[IFLA_GRE_LINK]		= { .type = NLA_U32 },
807c19e654dSHerbert Xu 	[IFLA_GRE_IFLAGS]	= { .type = NLA_U16 },
808c19e654dSHerbert Xu 	[IFLA_GRE_OFLAGS]	= { .type = NLA_U16 },
809c19e654dSHerbert Xu 	[IFLA_GRE_IKEY]		= { .type = NLA_U32 },
810c19e654dSHerbert Xu 	[IFLA_GRE_OKEY]		= { .type = NLA_U32 },
8114d74f8baSPatrick McHardy 	[IFLA_GRE_LOCAL]	= { .len = FIELD_SIZEOF(struct iphdr, saddr) },
8124d74f8baSPatrick McHardy 	[IFLA_GRE_REMOTE]	= { .len = FIELD_SIZEOF(struct iphdr, daddr) },
813c19e654dSHerbert Xu 	[IFLA_GRE_TTL]		= { .type = NLA_U8 },
814c19e654dSHerbert Xu 	[IFLA_GRE_TOS]		= { .type = NLA_U8 },
815c19e654dSHerbert Xu 	[IFLA_GRE_PMTUDISC]	= { .type = NLA_U8 },
8164565e991STom Herbert 	[IFLA_GRE_ENCAP_TYPE]	= { .type = NLA_U16 },
8174565e991STom Herbert 	[IFLA_GRE_ENCAP_FLAGS]	= { .type = NLA_U16 },
8184565e991STom Herbert 	[IFLA_GRE_ENCAP_SPORT]	= { .type = NLA_U16 },
8194565e991STom Herbert 	[IFLA_GRE_ENCAP_DPORT]	= { .type = NLA_U16 },
820c19e654dSHerbert Xu };
821c19e654dSHerbert Xu 
822c19e654dSHerbert Xu static struct rtnl_link_ops ipgre_link_ops __read_mostly = {
823c19e654dSHerbert Xu 	.kind		= "gre",
824c19e654dSHerbert Xu 	.maxtype	= IFLA_GRE_MAX,
825c19e654dSHerbert Xu 	.policy		= ipgre_policy,
826c19e654dSHerbert Xu 	.priv_size	= sizeof(struct ip_tunnel),
827c19e654dSHerbert Xu 	.setup		= ipgre_tunnel_setup,
828c19e654dSHerbert Xu 	.validate	= ipgre_tunnel_validate,
829c19e654dSHerbert Xu 	.newlink	= ipgre_newlink,
830c19e654dSHerbert Xu 	.changelink	= ipgre_changelink,
831c5441932SPravin B Shelar 	.dellink	= ip_tunnel_dellink,
832c19e654dSHerbert Xu 	.get_size	= ipgre_get_size,
833c19e654dSHerbert Xu 	.fill_info	= ipgre_fill_info,
8341728d4faSNicolas Dichtel 	.get_link_net	= ip_tunnel_get_link_net,
835c19e654dSHerbert Xu };
836c19e654dSHerbert Xu 
837e1a80002SHerbert Xu static struct rtnl_link_ops ipgre_tap_ops __read_mostly = {
838e1a80002SHerbert Xu 	.kind		= "gretap",
839e1a80002SHerbert Xu 	.maxtype	= IFLA_GRE_MAX,
840e1a80002SHerbert Xu 	.policy		= ipgre_policy,
841e1a80002SHerbert Xu 	.priv_size	= sizeof(struct ip_tunnel),
842e1a80002SHerbert Xu 	.setup		= ipgre_tap_setup,
843e1a80002SHerbert Xu 	.validate	= ipgre_tap_validate,
844e1a80002SHerbert Xu 	.newlink	= ipgre_newlink,
845e1a80002SHerbert Xu 	.changelink	= ipgre_changelink,
846c5441932SPravin B Shelar 	.dellink	= ip_tunnel_dellink,
847e1a80002SHerbert Xu 	.get_size	= ipgre_get_size,
848e1a80002SHerbert Xu 	.fill_info	= ipgre_fill_info,
8491728d4faSNicolas Dichtel 	.get_link_net	= ip_tunnel_get_link_net,
850e1a80002SHerbert Xu };
851e1a80002SHerbert Xu 
852c5441932SPravin B Shelar static int __net_init ipgre_tap_init_net(struct net *net)
853c5441932SPravin B Shelar {
854c5441932SPravin B Shelar 	return ip_tunnel_init_net(net, gre_tap_net_id, &ipgre_tap_ops, NULL);
855c5441932SPravin B Shelar }
856c5441932SPravin B Shelar 
857c5441932SPravin B Shelar static void __net_exit ipgre_tap_exit_net(struct net *net)
858c5441932SPravin B Shelar {
859c5441932SPravin B Shelar 	struct ip_tunnel_net *itn = net_generic(net, gre_tap_net_id);
8606c742e71SNicolas Dichtel 	ip_tunnel_delete_net(itn, &ipgre_tap_ops);
861c5441932SPravin B Shelar }
862c5441932SPravin B Shelar 
863c5441932SPravin B Shelar static struct pernet_operations ipgre_tap_net_ops = {
864c5441932SPravin B Shelar 	.init = ipgre_tap_init_net,
865c5441932SPravin B Shelar 	.exit = ipgre_tap_exit_net,
866c5441932SPravin B Shelar 	.id   = &gre_tap_net_id,
867c5441932SPravin B Shelar 	.size = sizeof(struct ip_tunnel_net),
868c5441932SPravin B Shelar };
8691da177e4SLinus Torvalds 
8701da177e4SLinus Torvalds static int __init ipgre_init(void)
8711da177e4SLinus Torvalds {
8721da177e4SLinus Torvalds 	int err;
8731da177e4SLinus Torvalds 
874058bd4d2SJoe Perches 	pr_info("GRE over IPv4 tunneling driver\n");
8751da177e4SLinus Torvalds 
876cfb8fbf2SEric W. Biederman 	err = register_pernet_device(&ipgre_net_ops);
87759a4c759SPavel Emelyanov 	if (err < 0)
878c2892f02SAlexey Dobriyan 		return err;
879c2892f02SAlexey Dobriyan 
880c5441932SPravin B Shelar 	err = register_pernet_device(&ipgre_tap_net_ops);
881c5441932SPravin B Shelar 	if (err < 0)
882c5441932SPravin B Shelar 		goto pnet_tap_faied;
883c5441932SPravin B Shelar 
884bda7bb46SPravin B Shelar 	err = gre_cisco_register(&ipgre_protocol);
885c2892f02SAlexey Dobriyan 	if (err < 0) {
886058bd4d2SJoe Perches 		pr_info("%s: can't add protocol\n", __func__);
887c2892f02SAlexey Dobriyan 		goto add_proto_failed;
888c2892f02SAlexey Dobriyan 	}
8897daa0004SPavel Emelyanov 
890c19e654dSHerbert Xu 	err = rtnl_link_register(&ipgre_link_ops);
891c19e654dSHerbert Xu 	if (err < 0)
892c19e654dSHerbert Xu 		goto rtnl_link_failed;
893c19e654dSHerbert Xu 
894e1a80002SHerbert Xu 	err = rtnl_link_register(&ipgre_tap_ops);
895e1a80002SHerbert Xu 	if (err < 0)
896e1a80002SHerbert Xu 		goto tap_ops_failed;
897e1a80002SHerbert Xu 
898c5441932SPravin B Shelar 	return 0;
899c19e654dSHerbert Xu 
900e1a80002SHerbert Xu tap_ops_failed:
901e1a80002SHerbert Xu 	rtnl_link_unregister(&ipgre_link_ops);
902c19e654dSHerbert Xu rtnl_link_failed:
903bda7bb46SPravin B Shelar 	gre_cisco_unregister(&ipgre_protocol);
904c2892f02SAlexey Dobriyan add_proto_failed:
905c5441932SPravin B Shelar 	unregister_pernet_device(&ipgre_tap_net_ops);
906c5441932SPravin B Shelar pnet_tap_faied:
907c2892f02SAlexey Dobriyan 	unregister_pernet_device(&ipgre_net_ops);
908c5441932SPravin B Shelar 	return err;
9091da177e4SLinus Torvalds }
9101da177e4SLinus Torvalds 
911db44575fSAlexey Kuznetsov static void __exit ipgre_fini(void)
9121da177e4SLinus Torvalds {
913e1a80002SHerbert Xu 	rtnl_link_unregister(&ipgre_tap_ops);
914c19e654dSHerbert Xu 	rtnl_link_unregister(&ipgre_link_ops);
915bda7bb46SPravin B Shelar 	gre_cisco_unregister(&ipgre_protocol);
916c5441932SPravin B Shelar 	unregister_pernet_device(&ipgre_tap_net_ops);
917c2892f02SAlexey Dobriyan 	unregister_pernet_device(&ipgre_net_ops);
9181da177e4SLinus Torvalds }
9191da177e4SLinus Torvalds 
9201da177e4SLinus Torvalds module_init(ipgre_init);
9211da177e4SLinus Torvalds module_exit(ipgre_fini);
9221da177e4SLinus Torvalds MODULE_LICENSE("GPL");
9234d74f8baSPatrick McHardy MODULE_ALIAS_RTNL_LINK("gre");
9244d74f8baSPatrick McHardy MODULE_ALIAS_RTNL_LINK("gretap");
9258909c9adSVasiliy Kulikov MODULE_ALIAS_NETDEV("gre0");
926c5441932SPravin B Shelar MODULE_ALIAS_NETDEV("gretap0");
927