xref: /linux/net/ipv4/ip_gre.c (revision d0522f1cd25edb796548f91e04766fa3cbc3b6df)
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>
207c0f6ba6SLinus Torvalds #include <linux/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>
272e15ea39SPravin B Shelar #include <linux/if_vlan.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>
502e15ea39SPravin B Shelar #include <net/dst_metadata.h>
5184e54fe0SWilliam Tu #include <net/erspan.h>
521da177e4SLinus Torvalds 
531da177e4SLinus Torvalds /*
541da177e4SLinus Torvalds    Problems & solutions
551da177e4SLinus Torvalds    --------------------
561da177e4SLinus Torvalds 
571da177e4SLinus Torvalds    1. The most important issue is detecting local dead loops.
581da177e4SLinus Torvalds    They would cause complete host lockup in transmit, which
591da177e4SLinus Torvalds    would be "resolved" by stack overflow or, if queueing is enabled,
601da177e4SLinus Torvalds    with infinite looping in net_bh.
611da177e4SLinus Torvalds 
621da177e4SLinus Torvalds    We cannot track such dead loops during route installation,
631da177e4SLinus Torvalds    it is infeasible task. The most general solutions would be
641da177e4SLinus Torvalds    to keep skb->encapsulation counter (sort of local ttl),
656d0722a2SEric Dumazet    and silently drop packet when it expires. It is a good
66bff52857Sstephen hemminger    solution, but it supposes maintaining new variable in ALL
671da177e4SLinus Torvalds    skb, even if no tunneling is used.
681da177e4SLinus Torvalds 
696d0722a2SEric Dumazet    Current solution: xmit_recursion breaks dead loops. This is a percpu
706d0722a2SEric Dumazet    counter, since when we enter the first ndo_xmit(), cpu migration is
716d0722a2SEric Dumazet    forbidden. We force an exit if this counter reaches RECURSION_LIMIT
721da177e4SLinus Torvalds 
731da177e4SLinus Torvalds    2. Networking dead loops would not kill routers, but would really
741da177e4SLinus Torvalds    kill network. IP hop limit plays role of "t->recursion" in this case,
751da177e4SLinus Torvalds    if we copy it from packet being encapsulated to upper header.
761da177e4SLinus Torvalds    It is very good solution, but it introduces two problems:
771da177e4SLinus Torvalds 
781da177e4SLinus Torvalds    - Routing protocols, using packets with ttl=1 (OSPF, RIP2),
791da177e4SLinus Torvalds      do not work over tunnels.
801da177e4SLinus Torvalds    - traceroute does not work. I planned to relay ICMP from tunnel,
811da177e4SLinus Torvalds      so that this problem would be solved and traceroute output
821da177e4SLinus Torvalds      would even more informative. This idea appeared to be wrong:
831da177e4SLinus Torvalds      only Linux complies to rfc1812 now (yes, guys, Linux is the only
841da177e4SLinus Torvalds      true router now :-)), all routers (at least, in neighbourhood of mine)
851da177e4SLinus Torvalds      return only 8 bytes of payload. It is the end.
861da177e4SLinus Torvalds 
871da177e4SLinus Torvalds    Hence, if we want that OSPF worked or traceroute said something reasonable,
881da177e4SLinus Torvalds    we should search for another solution.
891da177e4SLinus Torvalds 
901da177e4SLinus Torvalds    One of them is to parse packet trying to detect inner encapsulation
911da177e4SLinus Torvalds    made by our node. It is difficult or even impossible, especially,
92bff52857Sstephen hemminger    taking into account fragmentation. TO be short, ttl is not solution at all.
931da177e4SLinus Torvalds 
941da177e4SLinus Torvalds    Current solution: The solution was UNEXPECTEDLY SIMPLE.
951da177e4SLinus Torvalds    We force DF flag on tunnels with preconfigured hop limit,
961da177e4SLinus Torvalds    that is ALL. :-) Well, it does not remove the problem completely,
971da177e4SLinus Torvalds    but exponential growth of network traffic is changed to linear
981da177e4SLinus Torvalds    (branches, that exceed pmtu are pruned) and tunnel mtu
99bff52857Sstephen hemminger    rapidly degrades to value <68, where looping stops.
1001da177e4SLinus Torvalds    Yes, it is not good if there exists a router in the loop,
1011da177e4SLinus Torvalds    which does not force DF, even when encapsulating packets have DF set.
1021da177e4SLinus Torvalds    But it is not our problem! Nobody could accuse us, we made
1031da177e4SLinus Torvalds    all that we could make. Even if it is your gated who injected
1041da177e4SLinus Torvalds    fatal route to network, even if it were you who configured
1051da177e4SLinus Torvalds    fatal static route: you are innocent. :-)
1061da177e4SLinus Torvalds 
1071da177e4SLinus Torvalds    Alexey Kuznetsov.
1081da177e4SLinus Torvalds  */
1091da177e4SLinus Torvalds 
110eccc1bb8Sstephen hemminger static bool log_ecn_error = true;
111eccc1bb8Sstephen hemminger module_param(log_ecn_error, bool, 0644);
112eccc1bb8Sstephen hemminger MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN");
113eccc1bb8Sstephen hemminger 
114c19e654dSHerbert Xu static struct rtnl_link_ops ipgre_link_ops __read_mostly;
1151da177e4SLinus Torvalds static int ipgre_tunnel_init(struct net_device *dev);
1161a66a836SWilliam Tu static void erspan_build_header(struct sk_buff *skb,
117c69de58bSWilliam Tu 				u32 id, u32 index,
118a3222dc9SWilliam Tu 				bool truncate, bool is_ipv4);
119eb8ce741SPavel Emelyanov 
120c7d03a00SAlexey Dobriyan static unsigned int ipgre_net_id __read_mostly;
121c7d03a00SAlexey Dobriyan static unsigned int gre_tap_net_id __read_mostly;
12284e54fe0SWilliam Tu static unsigned int erspan_net_id __read_mostly;
123eb8ce741SPavel Emelyanov 
1249f57c67cSPravin B Shelar static void 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;
14620e1954fSEric Dumazet 	unsigned int data_len = 0;
1471da177e4SLinus Torvalds 	struct ip_tunnel *t;
148d2083287Sstephen hemminger 
1491da177e4SLinus Torvalds 	switch (type) {
1501da177e4SLinus Torvalds 	default:
1511da177e4SLinus Torvalds 	case ICMP_PARAMETERPROB:
1529f57c67cSPravin B Shelar 		return;
1531da177e4SLinus Torvalds 
1541da177e4SLinus Torvalds 	case ICMP_DEST_UNREACH:
1551da177e4SLinus Torvalds 		switch (code) {
1561da177e4SLinus Torvalds 		case ICMP_SR_FAILED:
1571da177e4SLinus Torvalds 		case ICMP_PORT_UNREACH:
1581da177e4SLinus Torvalds 			/* Impossible event. */
1599f57c67cSPravin B Shelar 			return;
1601da177e4SLinus Torvalds 		default:
1611da177e4SLinus Torvalds 			/* All others are translated to HOST_UNREACH.
1621da177e4SLinus Torvalds 			   rfc2003 contains "deep thoughts" about NET_UNREACH,
1631da177e4SLinus Torvalds 			   I believe they are just ether pollution. --ANK
1641da177e4SLinus Torvalds 			 */
1651da177e4SLinus Torvalds 			break;
1661da177e4SLinus Torvalds 		}
1671da177e4SLinus Torvalds 		break;
1689f57c67cSPravin B Shelar 
1691da177e4SLinus Torvalds 	case ICMP_TIME_EXCEEDED:
1701da177e4SLinus Torvalds 		if (code != ICMP_EXC_TTL)
1719f57c67cSPravin B Shelar 			return;
17220e1954fSEric Dumazet 		data_len = icmp_hdr(skb)->un.reserved[1] * 4; /* RFC 4884 4.1 */
1731da177e4SLinus Torvalds 		break;
17455be7a9cSDavid S. Miller 
17555be7a9cSDavid S. Miller 	case ICMP_REDIRECT:
17655be7a9cSDavid S. Miller 		break;
1771da177e4SLinus Torvalds 	}
1781da177e4SLinus Torvalds 
179bda7bb46SPravin B Shelar 	if (tpi->proto == htons(ETH_P_TEB))
180c5441932SPravin B Shelar 		itn = net_generic(net, gre_tap_net_id);
18151dc63e3SHaishuang Yan 	else if (tpi->proto == htons(ETH_P_ERSPAN) ||
18251dc63e3SHaishuang Yan 		 tpi->proto == htons(ETH_P_ERSPAN2))
18351dc63e3SHaishuang Yan 		itn = net_generic(net, erspan_net_id);
184c5441932SPravin B Shelar 	else
185c5441932SPravin B Shelar 		itn = net_generic(net, ipgre_net_id);
186c5441932SPravin B Shelar 
187c0c0c50fSDuan Jiong 	iph = (const struct iphdr *)(icmp_hdr(skb) + 1);
188bda7bb46SPravin B Shelar 	t = ip_tunnel_lookup(itn, skb->dev->ifindex, tpi->flags,
189bda7bb46SPravin B Shelar 			     iph->daddr, iph->saddr, tpi->key);
190d2083287Sstephen hemminger 
19151456b29SIan Morris 	if (!t)
1929f57c67cSPravin B Shelar 		return;
19336393395SDavid S. Miller 
1949b8c6d7bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6)
1959b8c6d7bSEric Dumazet        if (tpi->proto == htons(ETH_P_IPV6) &&
19620e1954fSEric Dumazet            !ip6_err_gen_icmpv6_unreach(skb, iph->ihl * 4 + tpi->hdr_len,
19720e1954fSEric Dumazet 				       type, data_len))
1989b8c6d7bSEric Dumazet                return;
1999b8c6d7bSEric Dumazet #endif
2009b8c6d7bSEric Dumazet 
20136393395SDavid S. Miller 	if (t->parms.iph.daddr == 0 ||
202f97c1e0cSJoe Perches 	    ipv4_is_multicast(t->parms.iph.daddr))
2039f57c67cSPravin B Shelar 		return;
2041da177e4SLinus Torvalds 
2051da177e4SLinus Torvalds 	if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED)
2069f57c67cSPravin B Shelar 		return;
2071da177e4SLinus Torvalds 
208da6185d8SWei Yongjun 	if (time_before(jiffies, t->err_time + IPTUNNEL_ERR_TIMEO))
2091da177e4SLinus Torvalds 		t->err_count++;
2101da177e4SLinus Torvalds 	else
2111da177e4SLinus Torvalds 		t->err_count = 1;
2121da177e4SLinus Torvalds 	t->err_time = jiffies;
2139f57c67cSPravin B Shelar }
2149f57c67cSPravin B Shelar 
2159f57c67cSPravin B Shelar static void gre_err(struct sk_buff *skb, u32 info)
2169f57c67cSPravin B Shelar {
2179f57c67cSPravin B Shelar 	/* All the routers (except for Linux) return only
2189f57c67cSPravin B Shelar 	 * 8 bytes of packet payload. It means, that precise relaying of
2199f57c67cSPravin B Shelar 	 * ICMP in the real Internet is absolutely infeasible.
2209f57c67cSPravin B Shelar 	 *
2219f57c67cSPravin B Shelar 	 * Moreover, Cisco "wise men" put GRE key to the third word
2229f57c67cSPravin B Shelar 	 * in GRE header. It makes impossible maintaining even soft
2239f57c67cSPravin B Shelar 	 * state for keyed
2249f57c67cSPravin B Shelar 	 * GRE tunnels with enabled checksum. Tell them "thank you".
2259f57c67cSPravin B Shelar 	 *
2269f57c67cSPravin B Shelar 	 * Well, I wonder, rfc1812 was written by Cisco employee,
2279f57c67cSPravin B Shelar 	 * what the hell these idiots break standards established
2289f57c67cSPravin B Shelar 	 * by themselves???
2299f57c67cSPravin B Shelar 	 */
2309f57c67cSPravin B Shelar 
231e582615aSEric Dumazet 	const struct iphdr *iph = (struct iphdr *)skb->data;
2329f57c67cSPravin B Shelar 	const int type = icmp_hdr(skb)->type;
2339f57c67cSPravin B Shelar 	const int code = icmp_hdr(skb)->code;
2349f57c67cSPravin B Shelar 	struct tnl_ptk_info tpi;
2359f57c67cSPravin B Shelar 
236b0350d51SHaishuang Yan 	if (gre_parse_header(skb, &tpi, NULL, htons(ETH_P_IP),
237b0350d51SHaishuang Yan 			     iph->ihl * 4) < 0)
2389f57c67cSPravin B Shelar 		return;
2399f57c67cSPravin B Shelar 
2409f57c67cSPravin B Shelar 	if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) {
2419f57c67cSPravin B Shelar 		ipv4_update_pmtu(skb, dev_net(skb->dev), info,
242d888f396SMaciej Żenczykowski 				 skb->dev->ifindex, IPPROTO_GRE);
2439f57c67cSPravin B Shelar 		return;
2449f57c67cSPravin B Shelar 	}
2459f57c67cSPravin B Shelar 	if (type == ICMP_REDIRECT) {
2461042caa7SMaciej Żenczykowski 		ipv4_redirect(skb, dev_net(skb->dev), skb->dev->ifindex,
2471042caa7SMaciej Żenczykowski 			      IPPROTO_GRE);
2489f57c67cSPravin B Shelar 		return;
2499f57c67cSPravin B Shelar 	}
2509f57c67cSPravin B Shelar 
2519f57c67cSPravin B Shelar 	ipgre_err(skb, info, &tpi);
2521da177e4SLinus Torvalds }
2531da177e4SLinus Torvalds 
25484e54fe0SWilliam Tu static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi,
25584e54fe0SWilliam Tu 		      int gre_hdr_len)
25684e54fe0SWilliam Tu {
25784e54fe0SWilliam Tu 	struct net *net = dev_net(skb->dev);
25884e54fe0SWilliam Tu 	struct metadata_dst *tun_dst = NULL;
2591d7e2ed2SWilliam Tu 	struct erspan_base_hdr *ershdr;
2601d7e2ed2SWilliam Tu 	struct erspan_metadata *pkt_md;
26184e54fe0SWilliam Tu 	struct ip_tunnel_net *itn;
26284e54fe0SWilliam Tu 	struct ip_tunnel *tunnel;
26384e54fe0SWilliam Tu 	const struct iphdr *iph;
2643df19283SWilliam Tu 	struct erspan_md2 *md2;
2651d7e2ed2SWilliam Tu 	int ver;
26684e54fe0SWilliam Tu 	int len;
26784e54fe0SWilliam Tu 
26884e54fe0SWilliam Tu 	itn = net_generic(net, erspan_net_id);
26984e54fe0SWilliam Tu 	len = gre_hdr_len + sizeof(*ershdr);
27084e54fe0SWilliam Tu 
2711d7e2ed2SWilliam Tu 	/* Check based hdr len */
27284e54fe0SWilliam Tu 	if (unlikely(!pskb_may_pull(skb, len)))
273c05fad57SHaishuang Yan 		return PACKET_REJECT;
27484e54fe0SWilliam Tu 
27584e54fe0SWilliam Tu 	iph = ip_hdr(skb);
2761d7e2ed2SWilliam Tu 	ershdr = (struct erspan_base_hdr *)(skb->data + gre_hdr_len);
277c69de58bSWilliam Tu 	ver = ershdr->ver;
27884e54fe0SWilliam Tu 
27984e54fe0SWilliam Tu 	/* The original GRE header does not have key field,
28084e54fe0SWilliam Tu 	 * Use ERSPAN 10-bit session ID as key.
28184e54fe0SWilliam Tu 	 */
282c69de58bSWilliam Tu 	tpi->key = cpu_to_be32(get_session_id(ershdr));
28384e54fe0SWilliam Tu 	tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex,
28484e54fe0SWilliam Tu 				  tpi->flags | TUNNEL_KEY,
28584e54fe0SWilliam Tu 				  iph->saddr, iph->daddr, tpi->key);
28684e54fe0SWilliam Tu 
28784e54fe0SWilliam Tu 	if (tunnel) {
2881d7e2ed2SWilliam Tu 		len = gre_hdr_len + erspan_hdr_len(ver);
2891d7e2ed2SWilliam Tu 		if (unlikely(!pskb_may_pull(skb, len)))
290ae3e1337SWilliam Tu 			return PACKET_REJECT;
2911d7e2ed2SWilliam Tu 
292d91e8db5SWilliam Tu 		ershdr = (struct erspan_base_hdr *)(skb->data + gre_hdr_len);
293d91e8db5SWilliam Tu 		pkt_md = (struct erspan_metadata *)(ershdr + 1);
294d91e8db5SWilliam Tu 
29584e54fe0SWilliam Tu 		if (__iptunnel_pull_header(skb,
2961d7e2ed2SWilliam Tu 					   len,
29784e54fe0SWilliam Tu 					   htons(ETH_P_TEB),
29884e54fe0SWilliam Tu 					   false, false) < 0)
29984e54fe0SWilliam Tu 			goto drop;
30084e54fe0SWilliam Tu 
3011a66a836SWilliam Tu 		if (tunnel->collect_md) {
3021a66a836SWilliam Tu 			struct ip_tunnel_info *info;
3031a66a836SWilliam Tu 			struct erspan_metadata *md;
3041a66a836SWilliam Tu 			__be64 tun_id;
3051a66a836SWilliam Tu 			__be16 flags;
3061a66a836SWilliam Tu 
3071a66a836SWilliam Tu 			tpi->flags |= TUNNEL_KEY;
3081a66a836SWilliam Tu 			flags = tpi->flags;
3091a66a836SWilliam Tu 			tun_id = key32_to_tunnel_id(tpi->key);
3101a66a836SWilliam Tu 
3111a66a836SWilliam Tu 			tun_dst = ip_tun_rx_dst(skb, flags,
3121a66a836SWilliam Tu 						tun_id, sizeof(*md));
3131a66a836SWilliam Tu 			if (!tun_dst)
3141a66a836SWilliam Tu 				return PACKET_REJECT;
3151a66a836SWilliam Tu 
3161a66a836SWilliam Tu 			md = ip_tunnel_info_opts(&tun_dst->u.tun_info);
317f551c91dSWilliam Tu 			md->version = ver;
3183df19283SWilliam Tu 			md2 = &md->u.md2;
3193df19283SWilliam Tu 			memcpy(md2, pkt_md, ver == 1 ? ERSPAN_V1_MDSIZE :
3203df19283SWilliam Tu 						       ERSPAN_V2_MDSIZE);
321f551c91dSWilliam Tu 
3221a66a836SWilliam Tu 			info = &tun_dst->u.tun_info;
3231a66a836SWilliam Tu 			info->key.tun_flags |= TUNNEL_ERSPAN_OPT;
3241a66a836SWilliam Tu 			info->options_len = sizeof(*md);
3251a66a836SWilliam Tu 		}
3261a66a836SWilliam Tu 
32784e54fe0SWilliam Tu 		skb_reset_mac_header(skb);
32884e54fe0SWilliam Tu 		ip_tunnel_rcv(tunnel, skb, tpi, tun_dst, log_ecn_error);
32984e54fe0SWilliam Tu 		return PACKET_RCVD;
33084e54fe0SWilliam Tu 	}
3315a64506bSHaishuang Yan 	return PACKET_REJECT;
3325a64506bSHaishuang Yan 
33384e54fe0SWilliam Tu drop:
33484e54fe0SWilliam Tu 	kfree_skb(skb);
33584e54fe0SWilliam Tu 	return PACKET_RCVD;
33684e54fe0SWilliam Tu }
33784e54fe0SWilliam Tu 
338125372faSJiri Benc static int __ipgre_rcv(struct sk_buff *skb, const struct tnl_ptk_info *tpi,
339125372faSJiri Benc 		       struct ip_tunnel_net *itn, int hdr_len, bool raw_proto)
3401da177e4SLinus Torvalds {
3412e15ea39SPravin B Shelar 	struct metadata_dst *tun_dst = NULL;
342b71d1d42SEric Dumazet 	const struct iphdr *iph;
3431da177e4SLinus Torvalds 	struct ip_tunnel *tunnel;
3441da177e4SLinus Torvalds 
345eddc9ec5SArnaldo Carvalho de Melo 	iph = ip_hdr(skb);
346bda7bb46SPravin B Shelar 	tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, tpi->flags,
347bda7bb46SPravin B Shelar 				  iph->saddr, iph->daddr, tpi->key);
3481da177e4SLinus Torvalds 
349d2083287Sstephen hemminger 	if (tunnel) {
350125372faSJiri Benc 		if (__iptunnel_pull_header(skb, hdr_len, tpi->proto,
351125372faSJiri Benc 					   raw_proto, false) < 0)
352244a797bSJiri Benc 			goto drop;
353244a797bSJiri Benc 
354e271c7b4SJiri Benc 		if (tunnel->dev->type != ARPHRD_NONE)
3550e3da5bbSTimo Teräs 			skb_pop_mac_header(skb);
356e271c7b4SJiri Benc 		else
357e271c7b4SJiri Benc 			skb_reset_mac_header(skb);
3582e15ea39SPravin B Shelar 		if (tunnel->collect_md) {
359c29a70d2SPravin B Shelar 			__be16 flags;
360c29a70d2SPravin B Shelar 			__be64 tun_id;
3612e15ea39SPravin B Shelar 
362c29a70d2SPravin B Shelar 			flags = tpi->flags & (TUNNEL_CSUM | TUNNEL_KEY);
363d817f432SAmir Vadai 			tun_id = key32_to_tunnel_id(tpi->key);
364c29a70d2SPravin B Shelar 			tun_dst = ip_tun_rx_dst(skb, flags, tun_id, 0);
3652e15ea39SPravin B Shelar 			if (!tun_dst)
3662e15ea39SPravin B Shelar 				return PACKET_REJECT;
3672e15ea39SPravin B Shelar 		}
3682e15ea39SPravin B Shelar 
3692e15ea39SPravin B Shelar 		ip_tunnel_rcv(tunnel, skb, tpi, tun_dst, log_ecn_error);
370bda7bb46SPravin B Shelar 		return PACKET_RCVD;
3711da177e4SLinus Torvalds 	}
372125372faSJiri Benc 	return PACKET_NEXT;
373244a797bSJiri Benc 
374244a797bSJiri Benc drop:
375244a797bSJiri Benc 	kfree_skb(skb);
376244a797bSJiri Benc 	return PACKET_RCVD;
3771da177e4SLinus Torvalds }
3781da177e4SLinus Torvalds 
379125372faSJiri Benc static int ipgre_rcv(struct sk_buff *skb, const struct tnl_ptk_info *tpi,
380125372faSJiri Benc 		     int hdr_len)
381125372faSJiri Benc {
382125372faSJiri Benc 	struct net *net = dev_net(skb->dev);
383125372faSJiri Benc 	struct ip_tunnel_net *itn;
384125372faSJiri Benc 	int res;
385125372faSJiri Benc 
386125372faSJiri Benc 	if (tpi->proto == htons(ETH_P_TEB))
387125372faSJiri Benc 		itn = net_generic(net, gre_tap_net_id);
388125372faSJiri Benc 	else
389125372faSJiri Benc 		itn = net_generic(net, ipgre_net_id);
390125372faSJiri Benc 
391125372faSJiri Benc 	res = __ipgre_rcv(skb, tpi, itn, hdr_len, false);
392125372faSJiri Benc 	if (res == PACKET_NEXT && tpi->proto == htons(ETH_P_TEB)) {
393125372faSJiri Benc 		/* ipgre tunnels in collect metadata mode should receive
394125372faSJiri Benc 		 * also ETH_P_TEB traffic.
395125372faSJiri Benc 		 */
396125372faSJiri Benc 		itn = net_generic(net, ipgre_net_id);
397125372faSJiri Benc 		res = __ipgre_rcv(skb, tpi, itn, hdr_len, true);
398125372faSJiri Benc 	}
399125372faSJiri Benc 	return res;
400125372faSJiri Benc }
401125372faSJiri Benc 
4029f57c67cSPravin B Shelar static int gre_rcv(struct sk_buff *skb)
4039f57c67cSPravin B Shelar {
4049f57c67cSPravin B Shelar 	struct tnl_ptk_info tpi;
4059f57c67cSPravin B Shelar 	bool csum_err = false;
40695f5c64cSTom Herbert 	int hdr_len;
4079f57c67cSPravin B Shelar 
4089f57c67cSPravin B Shelar #ifdef CONFIG_NET_IPGRE_BROADCAST
4099f57c67cSPravin B Shelar 	if (ipv4_is_multicast(ip_hdr(skb)->daddr)) {
4109f57c67cSPravin B Shelar 		/* Looped back packet, drop it! */
4119f57c67cSPravin B Shelar 		if (rt_is_output_route(skb_rtable(skb)))
4129f57c67cSPravin B Shelar 			goto drop;
4139f57c67cSPravin B Shelar 	}
4149f57c67cSPravin B Shelar #endif
4159f57c67cSPravin B Shelar 
416e582615aSEric Dumazet 	hdr_len = gre_parse_header(skb, &tpi, &csum_err, htons(ETH_P_IP), 0);
417f132ae7cSJiri Benc 	if (hdr_len < 0)
41895f5c64cSTom Herbert 		goto drop;
41995f5c64cSTom Herbert 
420f551c91dSWilliam Tu 	if (unlikely(tpi.proto == htons(ETH_P_ERSPAN) ||
421f551c91dSWilliam Tu 		     tpi.proto == htons(ETH_P_ERSPAN2))) {
42284e54fe0SWilliam Tu 		if (erspan_rcv(skb, &tpi, hdr_len) == PACKET_RCVD)
42384e54fe0SWilliam Tu 			return 0;
424dd8d5b8cSHaishuang Yan 		goto out;
42584e54fe0SWilliam Tu 	}
42684e54fe0SWilliam Tu 
427244a797bSJiri Benc 	if (ipgre_rcv(skb, &tpi, hdr_len) == PACKET_RCVD)
4289f57c67cSPravin B Shelar 		return 0;
4299f57c67cSPravin B Shelar 
430dd8d5b8cSHaishuang Yan out:
4319f57c67cSPravin B Shelar 	icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
4329f57c67cSPravin B Shelar drop:
4339f57c67cSPravin B Shelar 	kfree_skb(skb);
4349f57c67cSPravin B Shelar 	return 0;
4359f57c67cSPravin B Shelar }
4369f57c67cSPravin B Shelar 
437c5441932SPravin B Shelar static void __gre_xmit(struct sk_buff *skb, struct net_device *dev,
438c5441932SPravin B Shelar 		       const struct iphdr *tnl_params,
439c5441932SPravin B Shelar 		       __be16 proto)
440c5441932SPravin B Shelar {
441c5441932SPravin B Shelar 	struct ip_tunnel *tunnel = netdev_priv(dev);
442c5441932SPravin B Shelar 
443c5441932SPravin B Shelar 	if (tunnel->parms.o_flags & TUNNEL_SEQ)
444c5441932SPravin B Shelar 		tunnel->o_seqno++;
445cef401deSEric Dumazet 
446c5441932SPravin B Shelar 	/* Push GRE header. */
447182a352dSTom Herbert 	gre_build_header(skb, tunnel->tun_hlen,
448182a352dSTom Herbert 			 tunnel->parms.o_flags, proto, tunnel->parms.o_key,
449182a352dSTom Herbert 			 htonl(tunnel->o_seqno));
4501da177e4SLinus Torvalds 
451bf3d6a8fSNicolas Dichtel 	ip_tunnel_xmit(skb, dev, tnl_params, tnl_params->protocol);
4521da177e4SLinus Torvalds }
4531da177e4SLinus Torvalds 
454aed069dfSAlexander Duyck static int gre_handle_offloads(struct sk_buff *skb, bool csum)
455b2acd1dcSPravin B Shelar {
4566fa79666SEdward Cree 	return iptunnel_handle_offloads(skb, csum ? SKB_GSO_GRE_CSUM : SKB_GSO_GRE);
457b2acd1dcSPravin B Shelar }
458b2acd1dcSPravin B Shelar 
459fc4099f1SPravin B Shelar static struct rtable *gre_get_rt(struct sk_buff *skb,
460fc4099f1SPravin B Shelar 				 struct net_device *dev,
461fc4099f1SPravin B Shelar 				 struct flowi4 *fl,
462fc4099f1SPravin B Shelar 				 const struct ip_tunnel_key *key)
463fc4099f1SPravin B Shelar {
464fc4099f1SPravin B Shelar 	struct net *net = dev_net(dev);
465fc4099f1SPravin B Shelar 
466fc4099f1SPravin B Shelar 	memset(fl, 0, sizeof(*fl));
467fc4099f1SPravin B Shelar 	fl->daddr = key->u.ipv4.dst;
468fc4099f1SPravin B Shelar 	fl->saddr = key->u.ipv4.src;
469fc4099f1SPravin B Shelar 	fl->flowi4_tos = RT_TOS(key->tos);
470fc4099f1SPravin B Shelar 	fl->flowi4_mark = skb->mark;
471fc4099f1SPravin B Shelar 	fl->flowi4_proto = IPPROTO_GRE;
472fc4099f1SPravin B Shelar 
473fc4099f1SPravin B Shelar 	return ip_route_output_key(net, fl);
474fc4099f1SPravin B Shelar }
475fc4099f1SPravin B Shelar 
476862a03c3SWilliam Tu static struct rtable *prepare_fb_xmit(struct sk_buff *skb,
477862a03c3SWilliam Tu 				      struct net_device *dev,
478862a03c3SWilliam Tu 				      struct flowi4 *fl,
479862a03c3SWilliam Tu 				      int tunnel_hlen)
4802e15ea39SPravin B Shelar {
4812e15ea39SPravin B Shelar 	struct ip_tunnel_info *tun_info;
4822e15ea39SPravin B Shelar 	const struct ip_tunnel_key *key;
483db3c6139SDaniel Borkmann 	struct rtable *rt = NULL;
4842e15ea39SPravin B Shelar 	int min_headroom;
485db3c6139SDaniel Borkmann 	bool use_cache;
4862e15ea39SPravin B Shelar 	int err;
4872e15ea39SPravin B Shelar 
48861adedf3SJiri Benc 	tun_info = skb_tunnel_info(skb);
4892e15ea39SPravin B Shelar 	key = &tun_info->key;
490db3c6139SDaniel Borkmann 	use_cache = ip_tunnel_dst_cache_usable(skb, tun_info);
491862a03c3SWilliam Tu 
492db3c6139SDaniel Borkmann 	if (use_cache)
493862a03c3SWilliam Tu 		rt = dst_cache_get_ip4(&tun_info->dst_cache, &fl->saddr);
4943c1cb4d2SPaolo Abeni 	if (!rt) {
495862a03c3SWilliam Tu 		rt = gre_get_rt(skb, dev, fl, key);
4962e15ea39SPravin B Shelar 		if (IS_ERR(rt))
4972e15ea39SPravin B Shelar 			goto err_free_skb;
498db3c6139SDaniel Borkmann 		if (use_cache)
4993c1cb4d2SPaolo Abeni 			dst_cache_set_ip4(&tun_info->dst_cache, &rt->dst,
500862a03c3SWilliam Tu 					  fl->saddr);
5013c1cb4d2SPaolo Abeni 	}
5022e15ea39SPravin B Shelar 
5032e15ea39SPravin B Shelar 	min_headroom = LL_RESERVED_SPACE(rt->dst.dev) + rt->dst.header_len
5042e15ea39SPravin B Shelar 			+ tunnel_hlen + sizeof(struct iphdr);
5052e15ea39SPravin B Shelar 	if (skb_headroom(skb) < min_headroom || skb_header_cloned(skb)) {
5062e15ea39SPravin B Shelar 		int head_delta = SKB_DATA_ALIGN(min_headroom -
5072e15ea39SPravin B Shelar 						skb_headroom(skb) +
5082e15ea39SPravin B Shelar 						16);
5092e15ea39SPravin B Shelar 		err = pskb_expand_head(skb, max_t(int, head_delta, 0),
5102e15ea39SPravin B Shelar 				       0, GFP_ATOMIC);
5112e15ea39SPravin B Shelar 		if (unlikely(err))
5122e15ea39SPravin B Shelar 			goto err_free_rt;
5132e15ea39SPravin B Shelar 	}
514862a03c3SWilliam Tu 	return rt;
515862a03c3SWilliam Tu 
516862a03c3SWilliam Tu err_free_rt:
517862a03c3SWilliam Tu 	ip_rt_put(rt);
518862a03c3SWilliam Tu err_free_skb:
519862a03c3SWilliam Tu 	kfree_skb(skb);
520862a03c3SWilliam Tu 	dev->stats.tx_dropped++;
521862a03c3SWilliam Tu 	return NULL;
522862a03c3SWilliam Tu }
523862a03c3SWilliam Tu 
524862a03c3SWilliam Tu static void gre_fb_xmit(struct sk_buff *skb, struct net_device *dev,
525862a03c3SWilliam Tu 			__be16 proto)
526862a03c3SWilliam Tu {
52777a5196aSWilliam Tu 	struct ip_tunnel *tunnel = netdev_priv(dev);
528862a03c3SWilliam Tu 	struct ip_tunnel_info *tun_info;
529862a03c3SWilliam Tu 	const struct ip_tunnel_key *key;
530862a03c3SWilliam Tu 	struct rtable *rt = NULL;
531862a03c3SWilliam Tu 	struct flowi4 fl;
532862a03c3SWilliam Tu 	int tunnel_hlen;
533862a03c3SWilliam Tu 	__be16 df, flags;
534862a03c3SWilliam Tu 
535862a03c3SWilliam Tu 	tun_info = skb_tunnel_info(skb);
536862a03c3SWilliam Tu 	if (unlikely(!tun_info || !(tun_info->mode & IP_TUNNEL_INFO_TX) ||
537862a03c3SWilliam Tu 		     ip_tunnel_info_af(tun_info) != AF_INET))
538862a03c3SWilliam Tu 		goto err_free_skb;
539862a03c3SWilliam Tu 
540862a03c3SWilliam Tu 	key = &tun_info->key;
541862a03c3SWilliam Tu 	tunnel_hlen = gre_calc_hlen(key->tun_flags);
542862a03c3SWilliam Tu 
543862a03c3SWilliam Tu 	rt = prepare_fb_xmit(skb, dev, &fl, tunnel_hlen);
544862a03c3SWilliam Tu 	if (!rt)
545862a03c3SWilliam Tu 		return;
5462e15ea39SPravin B Shelar 
5472e15ea39SPravin B Shelar 	/* Push Tunnel header. */
548aed069dfSAlexander Duyck 	if (gre_handle_offloads(skb, !!(tun_info->key.tun_flags & TUNNEL_CSUM)))
5492e15ea39SPravin B Shelar 		goto err_free_rt;
5502e15ea39SPravin B Shelar 
55177a5196aSWilliam Tu 	flags = tun_info->key.tun_flags &
55277a5196aSWilliam Tu 		(TUNNEL_CSUM | TUNNEL_KEY | TUNNEL_SEQ);
553cba65321SDavid S. Miller 	gre_build_header(skb, tunnel_hlen, flags, proto,
55477a5196aSWilliam Tu 			 tunnel_id_to_key32(tun_info->key.tun_id),
55515746394SColin Ian King 			 (flags & TUNNEL_SEQ) ? htonl(tunnel->o_seqno++) : 0);
5562e15ea39SPravin B Shelar 
5572e15ea39SPravin B Shelar 	df = key->tun_flags & TUNNEL_DONT_FRAGMENT ?  htons(IP_DF) : 0;
558039f5062SPravin B Shelar 
559039f5062SPravin B Shelar 	iptunnel_xmit(skb->sk, rt, skb, fl.saddr, key->u.ipv4.dst, IPPROTO_GRE,
5607c383fb2SJiri Benc 		      key->tos, key->ttl, df, false);
5612e15ea39SPravin B Shelar 	return;
5622e15ea39SPravin B Shelar 
5632e15ea39SPravin B Shelar err_free_rt:
5642e15ea39SPravin B Shelar 	ip_rt_put(rt);
5652e15ea39SPravin B Shelar err_free_skb:
5662e15ea39SPravin B Shelar 	kfree_skb(skb);
5672e15ea39SPravin B Shelar 	dev->stats.tx_dropped++;
5682e15ea39SPravin B Shelar }
5692e15ea39SPravin B Shelar 
5701a66a836SWilliam Tu static void erspan_fb_xmit(struct sk_buff *skb, struct net_device *dev,
5711a66a836SWilliam Tu 			   __be16 proto)
5721a66a836SWilliam Tu {
5731a66a836SWilliam Tu 	struct ip_tunnel *tunnel = netdev_priv(dev);
5741a66a836SWilliam Tu 	struct ip_tunnel_info *tun_info;
5751a66a836SWilliam Tu 	const struct ip_tunnel_key *key;
5761a66a836SWilliam Tu 	struct erspan_metadata *md;
5771a66a836SWilliam Tu 	struct rtable *rt = NULL;
5781a66a836SWilliam Tu 	bool truncate = false;
5791a66a836SWilliam Tu 	struct flowi4 fl;
5801a66a836SWilliam Tu 	int tunnel_hlen;
581f551c91dSWilliam Tu 	int version;
5821a66a836SWilliam Tu 	__be16 df;
5831baf5ebfSWilliam Tu 	int nhoff;
584d5db21a3SWilliam Tu 	int thoff;
5851a66a836SWilliam Tu 
5861a66a836SWilliam Tu 	tun_info = skb_tunnel_info(skb);
5871a66a836SWilliam Tu 	if (unlikely(!tun_info || !(tun_info->mode & IP_TUNNEL_INFO_TX) ||
5881a66a836SWilliam Tu 		     ip_tunnel_info_af(tun_info) != AF_INET))
5891a66a836SWilliam Tu 		goto err_free_skb;
5901a66a836SWilliam Tu 
5911a66a836SWilliam Tu 	key = &tun_info->key;
592256c87c1SPieter Jansen van Vuuren 	if (!(tun_info->key.tun_flags & TUNNEL_ERSPAN_OPT))
593256c87c1SPieter Jansen van Vuuren 		goto err_free_rt;
594f551c91dSWilliam Tu 	md = ip_tunnel_info_opts(tun_info);
595f551c91dSWilliam Tu 	if (!md)
596f551c91dSWilliam Tu 		goto err_free_rt;
5971a66a836SWilliam Tu 
5981a66a836SWilliam Tu 	/* ERSPAN has fixed 8 byte GRE header */
599f551c91dSWilliam Tu 	version = md->version;
600f551c91dSWilliam Tu 	tunnel_hlen = 8 + erspan_hdr_len(version);
6011a66a836SWilliam Tu 
6021a66a836SWilliam Tu 	rt = prepare_fb_xmit(skb, dev, &fl, tunnel_hlen);
6031a66a836SWilliam Tu 	if (!rt)
6041a66a836SWilliam Tu 		return;
6051a66a836SWilliam Tu 
6061a66a836SWilliam Tu 	if (gre_handle_offloads(skb, false))
6071a66a836SWilliam Tu 		goto err_free_rt;
6081a66a836SWilliam Tu 
609f192970dSWilliam Tu 	if (skb->len > dev->mtu + dev->hard_header_len) {
610f192970dSWilliam Tu 		pskb_trim(skb, dev->mtu + dev->hard_header_len);
6111a66a836SWilliam Tu 		truncate = true;
6121a66a836SWilliam Tu 	}
6131a66a836SWilliam Tu 
6141baf5ebfSWilliam Tu 	nhoff = skb_network_header(skb) - skb_mac_header(skb);
6151baf5ebfSWilliam Tu 	if (skb->protocol == htons(ETH_P_IP) &&
6161baf5ebfSWilliam Tu 	    (ntohs(ip_hdr(skb)->tot_len) > skb->len - nhoff))
6171baf5ebfSWilliam Tu 		truncate = true;
6181baf5ebfSWilliam Tu 
619d5db21a3SWilliam Tu 	thoff = skb_transport_header(skb) - skb_mac_header(skb);
620d5db21a3SWilliam Tu 	if (skb->protocol == htons(ETH_P_IPV6) &&
621d5db21a3SWilliam Tu 	    (ntohs(ipv6_hdr(skb)->payload_len) > skb->len - thoff))
622d5db21a3SWilliam Tu 		truncate = true;
623d5db21a3SWilliam Tu 
624f551c91dSWilliam Tu 	if (version == 1) {
625c69de58bSWilliam Tu 		erspan_build_header(skb, ntohl(tunnel_id_to_key32(key->tun_id)),
6261d7e2ed2SWilliam Tu 				    ntohl(md->u.index), truncate, true);
627f551c91dSWilliam Tu 	} else if (version == 2) {
628c69de58bSWilliam Tu 		erspan_build_header_v2(skb,
629c69de58bSWilliam Tu 				       ntohl(tunnel_id_to_key32(key->tun_id)),
630c69de58bSWilliam Tu 				       md->u.md2.dir,
631c69de58bSWilliam Tu 				       get_hwid(&md->u.md2),
632c69de58bSWilliam Tu 				       truncate, true);
633f551c91dSWilliam Tu 	} else {
634f551c91dSWilliam Tu 		goto err_free_rt;
635f551c91dSWilliam Tu 	}
6361a66a836SWilliam Tu 
6371a66a836SWilliam Tu 	gre_build_header(skb, 8, TUNNEL_SEQ,
6381a66a836SWilliam Tu 			 htons(ETH_P_ERSPAN), 0, htonl(tunnel->o_seqno++));
6391a66a836SWilliam Tu 
6401a66a836SWilliam Tu 	df = key->tun_flags & TUNNEL_DONT_FRAGMENT ?  htons(IP_DF) : 0;
6411a66a836SWilliam Tu 
6421a66a836SWilliam Tu 	iptunnel_xmit(skb->sk, rt, skb, fl.saddr, key->u.ipv4.dst, IPPROTO_GRE,
6431a66a836SWilliam Tu 		      key->tos, key->ttl, df, false);
6441a66a836SWilliam Tu 	return;
6451a66a836SWilliam Tu 
6461a66a836SWilliam Tu err_free_rt:
6471a66a836SWilliam Tu 	ip_rt_put(rt);
6481a66a836SWilliam Tu err_free_skb:
6491a66a836SWilliam Tu 	kfree_skb(skb);
6501a66a836SWilliam Tu 	dev->stats.tx_dropped++;
6511a66a836SWilliam Tu }
6521a66a836SWilliam Tu 
653fc4099f1SPravin B Shelar static int gre_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
654fc4099f1SPravin B Shelar {
655fc4099f1SPravin B Shelar 	struct ip_tunnel_info *info = skb_tunnel_info(skb);
656fc4099f1SPravin B Shelar 	struct rtable *rt;
657fc4099f1SPravin B Shelar 	struct flowi4 fl4;
658fc4099f1SPravin B Shelar 
659fc4099f1SPravin B Shelar 	if (ip_tunnel_info_af(info) != AF_INET)
660fc4099f1SPravin B Shelar 		return -EINVAL;
661fc4099f1SPravin B Shelar 
662fc4099f1SPravin B Shelar 	rt = gre_get_rt(skb, dev, &fl4, &info->key);
663fc4099f1SPravin B Shelar 	if (IS_ERR(rt))
664fc4099f1SPravin B Shelar 		return PTR_ERR(rt);
665fc4099f1SPravin B Shelar 
666fc4099f1SPravin B Shelar 	ip_rt_put(rt);
667fc4099f1SPravin B Shelar 	info->key.u.ipv4.src = fl4.saddr;
668fc4099f1SPravin B Shelar 	return 0;
669fc4099f1SPravin B Shelar }
670fc4099f1SPravin B Shelar 
671c5441932SPravin B Shelar static netdev_tx_t ipgre_xmit(struct sk_buff *skb,
672c5441932SPravin B Shelar 			      struct net_device *dev)
673ee34c1ebSMichal Schmidt {
674c5441932SPravin B Shelar 	struct ip_tunnel *tunnel = netdev_priv(dev);
675c5441932SPravin B Shelar 	const struct iphdr *tnl_params;
676ee34c1ebSMichal Schmidt 
6772e15ea39SPravin B Shelar 	if (tunnel->collect_md) {
6782090714eSJiri Benc 		gre_fb_xmit(skb, dev, skb->protocol);
6792e15ea39SPravin B Shelar 		return NETDEV_TX_OK;
6802e15ea39SPravin B Shelar 	}
6812e15ea39SPravin B Shelar 
682c5441932SPravin B Shelar 	if (dev->header_ops) {
683c5441932SPravin B Shelar 		/* Need space for new headers */
684c5441932SPravin B Shelar 		if (skb_cow_head(skb, dev->needed_headroom -
6852bac7cb3SChen Gang 				      (tunnel->hlen + sizeof(struct iphdr))))
686c5441932SPravin B Shelar 			goto free_skb;
687ee34c1ebSMichal Schmidt 
688c5441932SPravin B Shelar 		tnl_params = (const struct iphdr *)skb->data;
689cbb1e85fSDavid S. Miller 
690c5441932SPravin B Shelar 		/* Pull skb since ip_tunnel_xmit() needs skb->data pointing
691c5441932SPravin B Shelar 		 * to gre header.
692c5441932SPravin B Shelar 		 */
693c5441932SPravin B Shelar 		skb_pull(skb, tunnel->hlen + sizeof(struct iphdr));
6948a0033a9STimo Teräs 		skb_reset_mac_header(skb);
695c5441932SPravin B Shelar 	} else {
696c5441932SPravin B Shelar 		if (skb_cow_head(skb, dev->needed_headroom))
697c5441932SPravin B Shelar 			goto free_skb;
698c5441932SPravin B Shelar 
699c5441932SPravin B Shelar 		tnl_params = &tunnel->parms.iph;
700ee34c1ebSMichal Schmidt 	}
701e1a80002SHerbert Xu 
702aed069dfSAlexander Duyck 	if (gre_handle_offloads(skb, !!(tunnel->parms.o_flags & TUNNEL_CSUM)))
703aed069dfSAlexander Duyck 		goto free_skb;
7048a0033a9STimo Teräs 
705c5441932SPravin B Shelar 	__gre_xmit(skb, dev, tnl_params, skb->protocol);
706c5441932SPravin B Shelar 	return NETDEV_TX_OK;
707c5441932SPravin B Shelar 
708c5441932SPravin B Shelar free_skb:
7093acfa1e7SEric Dumazet 	kfree_skb(skb);
710c5441932SPravin B Shelar 	dev->stats.tx_dropped++;
711c5441932SPravin B Shelar 	return NETDEV_TX_OK;
712ee34c1ebSMichal Schmidt }
713ee34c1ebSMichal Schmidt 
71484e54fe0SWilliam Tu static netdev_tx_t erspan_xmit(struct sk_buff *skb,
71584e54fe0SWilliam Tu 			       struct net_device *dev)
71684e54fe0SWilliam Tu {
71784e54fe0SWilliam Tu 	struct ip_tunnel *tunnel = netdev_priv(dev);
71884e54fe0SWilliam Tu 	bool truncate = false;
71984e54fe0SWilliam Tu 
7201a66a836SWilliam Tu 	if (tunnel->collect_md) {
7211a66a836SWilliam Tu 		erspan_fb_xmit(skb, dev, skb->protocol);
7221a66a836SWilliam Tu 		return NETDEV_TX_OK;
7231a66a836SWilliam Tu 	}
7241a66a836SWilliam Tu 
72584e54fe0SWilliam Tu 	if (gre_handle_offloads(skb, false))
72684e54fe0SWilliam Tu 		goto free_skb;
72784e54fe0SWilliam Tu 
72884e54fe0SWilliam Tu 	if (skb_cow_head(skb, dev->needed_headroom))
72984e54fe0SWilliam Tu 		goto free_skb;
73084e54fe0SWilliam Tu 
731f192970dSWilliam Tu 	if (skb->len > dev->mtu + dev->hard_header_len) {
732f192970dSWilliam Tu 		pskb_trim(skb, dev->mtu + dev->hard_header_len);
73384e54fe0SWilliam Tu 		truncate = true;
73484e54fe0SWilliam Tu 	}
73584e54fe0SWilliam Tu 
73684e54fe0SWilliam Tu 	/* Push ERSPAN header */
737f551c91dSWilliam Tu 	if (tunnel->erspan_ver == 1)
738c69de58bSWilliam Tu 		erspan_build_header(skb, ntohl(tunnel->parms.o_key),
739c69de58bSWilliam Tu 				    tunnel->index,
740a3222dc9SWilliam Tu 				    truncate, true);
74102f99df1SWilliam Tu 	else if (tunnel->erspan_ver == 2)
742c69de58bSWilliam Tu 		erspan_build_header_v2(skb, ntohl(tunnel->parms.o_key),
743f551c91dSWilliam Tu 				       tunnel->dir, tunnel->hwid,
744f551c91dSWilliam Tu 				       truncate, true);
74502f99df1SWilliam Tu 	else
74602f99df1SWilliam Tu 		goto free_skb;
747f551c91dSWilliam Tu 
74884e54fe0SWilliam Tu 	tunnel->parms.o_flags &= ~TUNNEL_KEY;
74984e54fe0SWilliam Tu 	__gre_xmit(skb, dev, &tunnel->parms.iph, htons(ETH_P_ERSPAN));
75084e54fe0SWilliam Tu 	return NETDEV_TX_OK;
75184e54fe0SWilliam Tu 
75284e54fe0SWilliam Tu free_skb:
75384e54fe0SWilliam Tu 	kfree_skb(skb);
75484e54fe0SWilliam Tu 	dev->stats.tx_dropped++;
75584e54fe0SWilliam Tu 	return NETDEV_TX_OK;
75684e54fe0SWilliam Tu }
75784e54fe0SWilliam Tu 
758c5441932SPravin B Shelar static netdev_tx_t gre_tap_xmit(struct sk_buff *skb,
759c5441932SPravin B Shelar 				struct net_device *dev)
760c5441932SPravin B Shelar {
761c5441932SPravin B Shelar 	struct ip_tunnel *tunnel = netdev_priv(dev);
762ee34c1ebSMichal Schmidt 
7632e15ea39SPravin B Shelar 	if (tunnel->collect_md) {
7642090714eSJiri Benc 		gre_fb_xmit(skb, dev, htons(ETH_P_TEB));
7652e15ea39SPravin B Shelar 		return NETDEV_TX_OK;
7662e15ea39SPravin B Shelar 	}
7672e15ea39SPravin B Shelar 
768aed069dfSAlexander Duyck 	if (gre_handle_offloads(skb, !!(tunnel->parms.o_flags & TUNNEL_CSUM)))
769aed069dfSAlexander Duyck 		goto free_skb;
770ee34c1ebSMichal Schmidt 
771c5441932SPravin B Shelar 	if (skb_cow_head(skb, dev->needed_headroom))
772c5441932SPravin B Shelar 		goto free_skb;
77342aa9162SHerbert Xu 
774c5441932SPravin B Shelar 	__gre_xmit(skb, dev, &tunnel->parms.iph, htons(ETH_P_TEB));
775c5441932SPravin B Shelar 	return NETDEV_TX_OK;
776c5441932SPravin B Shelar 
777c5441932SPravin B Shelar free_skb:
7783acfa1e7SEric Dumazet 	kfree_skb(skb);
779c5441932SPravin B Shelar 	dev->stats.tx_dropped++;
780c5441932SPravin B Shelar 	return NETDEV_TX_OK;
78168c33163SPravin B Shelar }
782ee34c1ebSMichal Schmidt 
783dd9d598cSXin Long static void ipgre_link_update(struct net_device *dev, bool set_mtu)
784dd9d598cSXin Long {
785dd9d598cSXin Long 	struct ip_tunnel *tunnel = netdev_priv(dev);
786dd9d598cSXin Long 	int len;
787dd9d598cSXin Long 
788dd9d598cSXin Long 	len = tunnel->tun_hlen;
789dd9d598cSXin Long 	tunnel->tun_hlen = gre_calc_hlen(tunnel->parms.o_flags);
790dd9d598cSXin Long 	len = tunnel->tun_hlen - len;
791dd9d598cSXin Long 	tunnel->hlen = tunnel->hlen + len;
792dd9d598cSXin Long 
793dd9d598cSXin Long 	dev->needed_headroom = dev->needed_headroom + len;
794dd9d598cSXin Long 	if (set_mtu)
795dd9d598cSXin Long 		dev->mtu = max_t(int, dev->mtu - len, 68);
796dd9d598cSXin Long 
797dd9d598cSXin Long 	if (!(tunnel->parms.o_flags & TUNNEL_SEQ)) {
798dd9d598cSXin Long 		if (!(tunnel->parms.o_flags & TUNNEL_CSUM) ||
799dd9d598cSXin Long 		    tunnel->encap.type == TUNNEL_ENCAP_NONE) {
800dd9d598cSXin Long 			dev->features |= NETIF_F_GSO_SOFTWARE;
801dd9d598cSXin Long 			dev->hw_features |= NETIF_F_GSO_SOFTWARE;
8021cc5954fSSabrina Dubroca 		} else {
8031cc5954fSSabrina Dubroca 			dev->features &= ~NETIF_F_GSO_SOFTWARE;
8041cc5954fSSabrina Dubroca 			dev->hw_features &= ~NETIF_F_GSO_SOFTWARE;
805dd9d598cSXin Long 		}
806dd9d598cSXin Long 		dev->features |= NETIF_F_LLTX;
8071cc5954fSSabrina Dubroca 	} else {
8081cc5954fSSabrina Dubroca 		dev->hw_features &= ~NETIF_F_GSO_SOFTWARE;
8091cc5954fSSabrina Dubroca 		dev->features &= ~(NETIF_F_LLTX | NETIF_F_GSO_SOFTWARE);
810dd9d598cSXin Long 	}
811dd9d598cSXin Long }
812dd9d598cSXin Long 
813c5441932SPravin B Shelar static int ipgre_tunnel_ioctl(struct net_device *dev,
814c5441932SPravin B Shelar 			      struct ifreq *ifr, int cmd)
8151da177e4SLinus Torvalds {
8161da177e4SLinus Torvalds 	struct ip_tunnel_parm p;
817a0efab67SXin Long 	int err;
8181da177e4SLinus Torvalds 
8191da177e4SLinus Torvalds 	if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
820c5441932SPravin B Shelar 		return -EFAULT;
821a0efab67SXin Long 
8226c734fb8SCong Wang 	if (cmd == SIOCADDTUNNEL || cmd == SIOCCHGTUNNEL) {
8231da177e4SLinus Torvalds 		if (p.iph.version != 4 || p.iph.protocol != IPPROTO_GRE ||
8241da177e4SLinus Torvalds 		    p.iph.ihl != 5 || (p.iph.frag_off & htons(~IP_DF)) ||
8256c734fb8SCong Wang 		    ((p.i_flags | p.o_flags) & (GRE_VERSION | GRE_ROUTING)))
8261da177e4SLinus Torvalds 			return -EINVAL;
827c5441932SPravin B Shelar 	}
828a0efab67SXin Long 
829c5441932SPravin B Shelar 	p.i_flags = gre_flags_to_tnl_flags(p.i_flags);
830c5441932SPravin B Shelar 	p.o_flags = gre_flags_to_tnl_flags(p.o_flags);
831c5441932SPravin B Shelar 
832c5441932SPravin B Shelar 	err = ip_tunnel_ioctl(dev, &p, cmd);
833c5441932SPravin B Shelar 	if (err)
834c5441932SPravin B Shelar 		return err;
835c5441932SPravin B Shelar 
836a0efab67SXin Long 	if (cmd == SIOCCHGTUNNEL) {
837a0efab67SXin Long 		struct ip_tunnel *t = netdev_priv(dev);
838a0efab67SXin Long 
839a0efab67SXin Long 		t->parms.i_flags = p.i_flags;
840a0efab67SXin Long 		t->parms.o_flags = p.o_flags;
841a0efab67SXin Long 
842a0efab67SXin Long 		if (strcmp(dev->rtnl_link_ops->kind, "erspan"))
843a0efab67SXin Long 			ipgre_link_update(dev, true);
844a0efab67SXin Long 	}
845a0efab67SXin Long 
84695f5c64cSTom Herbert 	p.i_flags = gre_tnl_flags_to_gre_flags(p.i_flags);
84795f5c64cSTom Herbert 	p.o_flags = gre_tnl_flags_to_gre_flags(p.o_flags);
848c5441932SPravin B Shelar 
849c5441932SPravin B Shelar 	if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p)))
850c5441932SPravin B Shelar 		return -EFAULT;
851a0efab67SXin Long 
8521da177e4SLinus Torvalds 	return 0;
8531da177e4SLinus Torvalds }
8541da177e4SLinus Torvalds 
8551da177e4SLinus Torvalds /* Nice toy. Unfortunately, useless in real life :-)
8561da177e4SLinus Torvalds    It allows to construct virtual multiprotocol broadcast "LAN"
8571da177e4SLinus Torvalds    over the Internet, provided multicast routing is tuned.
8581da177e4SLinus Torvalds 
8591da177e4SLinus Torvalds 
8601da177e4SLinus Torvalds    I have no idea was this bicycle invented before me,
8611da177e4SLinus Torvalds    so that I had to set ARPHRD_IPGRE to a random value.
8621da177e4SLinus Torvalds    I have an impression, that Cisco could make something similar,
8631da177e4SLinus Torvalds    but this feature is apparently missing in IOS<=11.2(8).
8641da177e4SLinus Torvalds 
8651da177e4SLinus Torvalds    I set up 10.66.66/24 and fec0:6666:6666::0/96 as virtual networks
8661da177e4SLinus Torvalds    with broadcast 224.66.66.66. If you have access to mbone, play with me :-)
8671da177e4SLinus Torvalds 
8681da177e4SLinus Torvalds    ping -t 255 224.66.66.66
8691da177e4SLinus Torvalds 
8701da177e4SLinus Torvalds    If nobody answers, mbone does not work.
8711da177e4SLinus Torvalds 
8721da177e4SLinus Torvalds    ip tunnel add Universe mode gre remote 224.66.66.66 local <Your_real_addr> ttl 255
8731da177e4SLinus Torvalds    ip addr add 10.66.66.<somewhat>/24 dev Universe
8741da177e4SLinus Torvalds    ifconfig Universe up
8751da177e4SLinus Torvalds    ifconfig Universe add fe80::<Your_real_addr>/10
8761da177e4SLinus Torvalds    ifconfig Universe add fec0:6666:6666::<Your_real_addr>/96
8771da177e4SLinus Torvalds    ftp 10.66.66.66
8781da177e4SLinus Torvalds    ...
8791da177e4SLinus Torvalds    ftp fec0:6666:6666::193.233.7.65
8801da177e4SLinus Torvalds    ...
8811da177e4SLinus Torvalds  */
8823b04dddeSStephen Hemminger static int ipgre_header(struct sk_buff *skb, struct net_device *dev,
8833b04dddeSStephen Hemminger 			unsigned short type,
8841507850bSEric Dumazet 			const void *daddr, const void *saddr, unsigned int len)
8851da177e4SLinus Torvalds {
8862941a486SPatrick McHardy 	struct ip_tunnel *t = netdev_priv(dev);
887c5441932SPravin B Shelar 	struct iphdr *iph;
888c5441932SPravin B Shelar 	struct gre_base_hdr *greh;
889c5441932SPravin B Shelar 
890d58ff351SJohannes Berg 	iph = skb_push(skb, t->hlen + sizeof(*iph));
891c5441932SPravin B Shelar 	greh = (struct gre_base_hdr *)(iph+1);
89295f5c64cSTom Herbert 	greh->flags = gre_tnl_flags_to_gre_flags(t->parms.o_flags);
893c5441932SPravin B Shelar 	greh->protocol = htons(type);
8941da177e4SLinus Torvalds 
8951da177e4SLinus Torvalds 	memcpy(iph, &t->parms.iph, sizeof(struct iphdr));
8961da177e4SLinus Torvalds 
897c5441932SPravin B Shelar 	/* Set the source hardware address. */
8981da177e4SLinus Torvalds 	if (saddr)
8991da177e4SLinus Torvalds 		memcpy(&iph->saddr, saddr, 4);
9006d55cb91STimo Teräs 	if (daddr)
9011da177e4SLinus Torvalds 		memcpy(&iph->daddr, daddr, 4);
9026d55cb91STimo Teräs 	if (iph->daddr)
90377a482bdSTimo Teräs 		return t->hlen + sizeof(*iph);
9041da177e4SLinus Torvalds 
905c5441932SPravin B Shelar 	return -(t->hlen + sizeof(*iph));
9061da177e4SLinus Torvalds }
9071da177e4SLinus Torvalds 
9086a5f44d7STimo Teras static int ipgre_header_parse(const struct sk_buff *skb, unsigned char *haddr)
9096a5f44d7STimo Teras {
910b71d1d42SEric Dumazet 	const struct iphdr *iph = (const struct iphdr *) skb_mac_header(skb);
9116a5f44d7STimo Teras 	memcpy(haddr, &iph->saddr, 4);
9126a5f44d7STimo Teras 	return 4;
9136a5f44d7STimo Teras }
9146a5f44d7STimo Teras 
9153b04dddeSStephen Hemminger static const struct header_ops ipgre_header_ops = {
9163b04dddeSStephen Hemminger 	.create	= ipgre_header,
9176a5f44d7STimo Teras 	.parse	= ipgre_header_parse,
9183b04dddeSStephen Hemminger };
9193b04dddeSStephen Hemminger 
9206a5f44d7STimo Teras #ifdef CONFIG_NET_IPGRE_BROADCAST
9211da177e4SLinus Torvalds static int ipgre_open(struct net_device *dev)
9221da177e4SLinus Torvalds {
9232941a486SPatrick McHardy 	struct ip_tunnel *t = netdev_priv(dev);
9241da177e4SLinus Torvalds 
925f97c1e0cSJoe Perches 	if (ipv4_is_multicast(t->parms.iph.daddr)) {
926cbb1e85fSDavid S. Miller 		struct flowi4 fl4;
927cbb1e85fSDavid S. Miller 		struct rtable *rt;
928cbb1e85fSDavid S. Miller 
929b57708adSNicolas Dichtel 		rt = ip_route_output_gre(t->net, &fl4,
93078fbfd8aSDavid S. Miller 					 t->parms.iph.daddr,
93178fbfd8aSDavid S. Miller 					 t->parms.iph.saddr,
93278fbfd8aSDavid S. Miller 					 t->parms.o_key,
93378fbfd8aSDavid S. Miller 					 RT_TOS(t->parms.iph.tos),
93478fbfd8aSDavid S. Miller 					 t->parms.link);
935b23dd4feSDavid S. Miller 		if (IS_ERR(rt))
9361da177e4SLinus Torvalds 			return -EADDRNOTAVAIL;
937d8d1f30bSChangli Gao 		dev = rt->dst.dev;
9381da177e4SLinus Torvalds 		ip_rt_put(rt);
93951456b29SIan Morris 		if (!__in_dev_get_rtnl(dev))
9401da177e4SLinus Torvalds 			return -EADDRNOTAVAIL;
9411da177e4SLinus Torvalds 		t->mlink = dev->ifindex;
942e5ed6399SHerbert Xu 		ip_mc_inc_group(__in_dev_get_rtnl(dev), t->parms.iph.daddr);
9431da177e4SLinus Torvalds 	}
9441da177e4SLinus Torvalds 	return 0;
9451da177e4SLinus Torvalds }
9461da177e4SLinus Torvalds 
9471da177e4SLinus Torvalds static int ipgre_close(struct net_device *dev)
9481da177e4SLinus Torvalds {
9492941a486SPatrick McHardy 	struct ip_tunnel *t = netdev_priv(dev);
950b8c26a33SStephen Hemminger 
951f97c1e0cSJoe Perches 	if (ipv4_is_multicast(t->parms.iph.daddr) && t->mlink) {
9527fee0ca2SDenis V. Lunev 		struct in_device *in_dev;
953b57708adSNicolas Dichtel 		in_dev = inetdev_by_index(t->net, t->mlink);
9548723e1b4SEric Dumazet 		if (in_dev)
9551da177e4SLinus Torvalds 			ip_mc_dec_group(in_dev, t->parms.iph.daddr);
9561da177e4SLinus Torvalds 	}
9571da177e4SLinus Torvalds 	return 0;
9581da177e4SLinus Torvalds }
9591da177e4SLinus Torvalds #endif
9601da177e4SLinus Torvalds 
961b8c26a33SStephen Hemminger static const struct net_device_ops ipgre_netdev_ops = {
962b8c26a33SStephen Hemminger 	.ndo_init		= ipgre_tunnel_init,
963c5441932SPravin B Shelar 	.ndo_uninit		= ip_tunnel_uninit,
964b8c26a33SStephen Hemminger #ifdef CONFIG_NET_IPGRE_BROADCAST
965b8c26a33SStephen Hemminger 	.ndo_open		= ipgre_open,
966b8c26a33SStephen Hemminger 	.ndo_stop		= ipgre_close,
967b8c26a33SStephen Hemminger #endif
968c5441932SPravin B Shelar 	.ndo_start_xmit		= ipgre_xmit,
969b8c26a33SStephen Hemminger 	.ndo_do_ioctl		= ipgre_tunnel_ioctl,
970c5441932SPravin B Shelar 	.ndo_change_mtu		= ip_tunnel_change_mtu,
971c5441932SPravin B Shelar 	.ndo_get_stats64	= ip_tunnel_get_stats64,
9721e99584bSNicolas Dichtel 	.ndo_get_iflink		= ip_tunnel_get_iflink,
973b8c26a33SStephen Hemminger };
974b8c26a33SStephen Hemminger 
9756b78f16eSEric Dumazet #define GRE_FEATURES (NETIF_F_SG |		\
9766b78f16eSEric Dumazet 		      NETIF_F_FRAGLIST |	\
9776b78f16eSEric Dumazet 		      NETIF_F_HIGHDMA |		\
9786b78f16eSEric Dumazet 		      NETIF_F_HW_CSUM)
9796b78f16eSEric Dumazet 
9801da177e4SLinus Torvalds static void ipgre_tunnel_setup(struct net_device *dev)
9811da177e4SLinus Torvalds {
982b8c26a33SStephen Hemminger 	dev->netdev_ops		= &ipgre_netdev_ops;
9835a455275SNicolas Dichtel 	dev->type		= ARPHRD_IPGRE;
984c5441932SPravin B Shelar 	ip_tunnel_setup(dev, ipgre_net_id);
985c5441932SPravin B Shelar }
9861da177e4SLinus Torvalds 
987c5441932SPravin B Shelar static void __gre_tunnel_init(struct net_device *dev)
988c5441932SPravin B Shelar {
989c5441932SPravin B Shelar 	struct ip_tunnel *tunnel;
990c5441932SPravin B Shelar 
991c5441932SPravin B Shelar 	tunnel = netdev_priv(dev);
99295f5c64cSTom Herbert 	tunnel->tun_hlen = gre_calc_hlen(tunnel->parms.o_flags);
993c5441932SPravin B Shelar 	tunnel->parms.iph.protocol = IPPROTO_GRE;
994c5441932SPravin B Shelar 
9954565e991STom Herbert 	tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen;
9964565e991STom Herbert 
997b57708adSNicolas Dichtel 	dev->features		|= GRE_FEATURES;
9986b78f16eSEric Dumazet 	dev->hw_features	|= GRE_FEATURES;
999c5441932SPravin B Shelar 
1000c5441932SPravin B Shelar 	if (!(tunnel->parms.o_flags & TUNNEL_SEQ)) {
1001a0ca153fSAlexander Duyck 		/* TCP offload with GRE SEQ is not supported, nor
1002a0ca153fSAlexander Duyck 		 * can we support 2 levels of outer headers requiring
1003a0ca153fSAlexander Duyck 		 * an update.
1004a0ca153fSAlexander Duyck 		 */
1005a0ca153fSAlexander Duyck 		if (!(tunnel->parms.o_flags & TUNNEL_CSUM) ||
1006a0ca153fSAlexander Duyck 		    (tunnel->encap.type == TUNNEL_ENCAP_NONE)) {
1007c5441932SPravin B Shelar 			dev->features    |= NETIF_F_GSO_SOFTWARE;
1008c5441932SPravin B Shelar 			dev->hw_features |= NETIF_F_GSO_SOFTWARE;
1009a0ca153fSAlexander Duyck 		}
1010a0ca153fSAlexander Duyck 
1011c5441932SPravin B Shelar 		/* Can use a lockless transmit, unless we generate
1012c5441932SPravin B Shelar 		 * output sequences
1013c5441932SPravin B Shelar 		 */
1014c5441932SPravin B Shelar 		dev->features |= NETIF_F_LLTX;
1015c5441932SPravin B Shelar 	}
10161da177e4SLinus Torvalds }
10171da177e4SLinus Torvalds 
10181da177e4SLinus Torvalds static int ipgre_tunnel_init(struct net_device *dev)
10191da177e4SLinus Torvalds {
1020c5441932SPravin B Shelar 	struct ip_tunnel *tunnel = netdev_priv(dev);
1021c5441932SPravin B Shelar 	struct iphdr *iph = &tunnel->parms.iph;
10221da177e4SLinus Torvalds 
1023c5441932SPravin B Shelar 	__gre_tunnel_init(dev);
10241da177e4SLinus Torvalds 
1025c5441932SPravin B Shelar 	memcpy(dev->dev_addr, &iph->saddr, 4);
1026c5441932SPravin B Shelar 	memcpy(dev->broadcast, &iph->daddr, 4);
10271da177e4SLinus Torvalds 
1028c5441932SPravin B Shelar 	dev->flags		= IFF_NOARP;
102902875878SEric Dumazet 	netif_keep_dst(dev);
1030c5441932SPravin B Shelar 	dev->addr_len		= 4;
10311da177e4SLinus Torvalds 
1032a64b04d8SJiri Benc 	if (iph->daddr && !tunnel->collect_md) {
10331da177e4SLinus Torvalds #ifdef CONFIG_NET_IPGRE_BROADCAST
1034f97c1e0cSJoe Perches 		if (ipv4_is_multicast(iph->daddr)) {
10351da177e4SLinus Torvalds 			if (!iph->saddr)
10361da177e4SLinus Torvalds 				return -EINVAL;
10371da177e4SLinus Torvalds 			dev->flags = IFF_BROADCAST;
10383b04dddeSStephen Hemminger 			dev->header_ops = &ipgre_header_ops;
10391da177e4SLinus Torvalds 		}
10401da177e4SLinus Torvalds #endif
1041a64b04d8SJiri Benc 	} else if (!tunnel->collect_md) {
10426a5f44d7STimo Teras 		dev->header_ops = &ipgre_header_ops;
1043a64b04d8SJiri Benc 	}
10441da177e4SLinus Torvalds 
1045c5441932SPravin B Shelar 	return ip_tunnel_init(dev);
104660769a5dSEric Dumazet }
104760769a5dSEric Dumazet 
10489f57c67cSPravin B Shelar static const struct gre_protocol ipgre_protocol = {
10499f57c67cSPravin B Shelar 	.handler     = gre_rcv,
10509f57c67cSPravin B Shelar 	.err_handler = gre_err,
10511da177e4SLinus Torvalds };
10521da177e4SLinus Torvalds 
10532c8c1e72SAlexey Dobriyan static int __net_init ipgre_init_net(struct net *net)
105459a4c759SPavel Emelyanov {
1055c5441932SPravin B Shelar 	return ip_tunnel_init_net(net, ipgre_net_id, &ipgre_link_ops, NULL);
105659a4c759SPavel Emelyanov }
105759a4c759SPavel Emelyanov 
105864bc1781SEric Dumazet static void __net_exit ipgre_exit_batch_net(struct list_head *list_net)
105959a4c759SPavel Emelyanov {
106064bc1781SEric Dumazet 	ip_tunnel_delete_nets(list_net, ipgre_net_id, &ipgre_link_ops);
106159a4c759SPavel Emelyanov }
106259a4c759SPavel Emelyanov 
106359a4c759SPavel Emelyanov static struct pernet_operations ipgre_net_ops = {
106459a4c759SPavel Emelyanov 	.init = ipgre_init_net,
106564bc1781SEric Dumazet 	.exit_batch = ipgre_exit_batch_net,
1066cfb8fbf2SEric W. Biederman 	.id   = &ipgre_net_id,
1067c5441932SPravin B Shelar 	.size = sizeof(struct ip_tunnel_net),
106859a4c759SPavel Emelyanov };
10691da177e4SLinus Torvalds 
1070a8b8a889SMatthias Schiffer static int ipgre_tunnel_validate(struct nlattr *tb[], struct nlattr *data[],
1071a8b8a889SMatthias Schiffer 				 struct netlink_ext_ack *extack)
1072c19e654dSHerbert Xu {
1073c19e654dSHerbert Xu 	__be16 flags;
1074c19e654dSHerbert Xu 
1075c19e654dSHerbert Xu 	if (!data)
1076c19e654dSHerbert Xu 		return 0;
1077c19e654dSHerbert Xu 
1078c19e654dSHerbert Xu 	flags = 0;
1079c19e654dSHerbert Xu 	if (data[IFLA_GRE_IFLAGS])
1080c19e654dSHerbert Xu 		flags |= nla_get_be16(data[IFLA_GRE_IFLAGS]);
1081c19e654dSHerbert Xu 	if (data[IFLA_GRE_OFLAGS])
1082c19e654dSHerbert Xu 		flags |= nla_get_be16(data[IFLA_GRE_OFLAGS]);
1083c19e654dSHerbert Xu 	if (flags & (GRE_VERSION|GRE_ROUTING))
1084c19e654dSHerbert Xu 		return -EINVAL;
1085c19e654dSHerbert Xu 
1086946b636fSJiri Benc 	if (data[IFLA_GRE_COLLECT_METADATA] &&
1087946b636fSJiri Benc 	    data[IFLA_GRE_ENCAP_TYPE] &&
1088946b636fSJiri Benc 	    nla_get_u16(data[IFLA_GRE_ENCAP_TYPE]) != TUNNEL_ENCAP_NONE)
1089946b636fSJiri Benc 		return -EINVAL;
1090946b636fSJiri Benc 
1091c19e654dSHerbert Xu 	return 0;
1092c19e654dSHerbert Xu }
1093c19e654dSHerbert Xu 
1094a8b8a889SMatthias Schiffer static int ipgre_tap_validate(struct nlattr *tb[], struct nlattr *data[],
1095a8b8a889SMatthias Schiffer 			      struct netlink_ext_ack *extack)
1096e1a80002SHerbert Xu {
1097e1a80002SHerbert Xu 	__be32 daddr;
1098e1a80002SHerbert Xu 
1099e1a80002SHerbert Xu 	if (tb[IFLA_ADDRESS]) {
1100e1a80002SHerbert Xu 		if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN)
1101e1a80002SHerbert Xu 			return -EINVAL;
1102e1a80002SHerbert Xu 		if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS])))
1103e1a80002SHerbert Xu 			return -EADDRNOTAVAIL;
1104e1a80002SHerbert Xu 	}
1105e1a80002SHerbert Xu 
1106e1a80002SHerbert Xu 	if (!data)
1107e1a80002SHerbert Xu 		goto out;
1108e1a80002SHerbert Xu 
1109e1a80002SHerbert Xu 	if (data[IFLA_GRE_REMOTE]) {
1110e1a80002SHerbert Xu 		memcpy(&daddr, nla_data(data[IFLA_GRE_REMOTE]), 4);
1111e1a80002SHerbert Xu 		if (!daddr)
1112e1a80002SHerbert Xu 			return -EINVAL;
1113e1a80002SHerbert Xu 	}
1114e1a80002SHerbert Xu 
1115e1a80002SHerbert Xu out:
1116a8b8a889SMatthias Schiffer 	return ipgre_tunnel_validate(tb, data, extack);
1117e1a80002SHerbert Xu }
1118e1a80002SHerbert Xu 
111984e54fe0SWilliam Tu static int erspan_validate(struct nlattr *tb[], struct nlattr *data[],
112084e54fe0SWilliam Tu 			   struct netlink_ext_ack *extack)
112184e54fe0SWilliam Tu {
112284e54fe0SWilliam Tu 	__be16 flags = 0;
112384e54fe0SWilliam Tu 	int ret;
112484e54fe0SWilliam Tu 
112584e54fe0SWilliam Tu 	if (!data)
112684e54fe0SWilliam Tu 		return 0;
112784e54fe0SWilliam Tu 
112884e54fe0SWilliam Tu 	ret = ipgre_tap_validate(tb, data, extack);
112984e54fe0SWilliam Tu 	if (ret)
113084e54fe0SWilliam Tu 		return ret;
113184e54fe0SWilliam Tu 
113284e54fe0SWilliam Tu 	/* ERSPAN should only have GRE sequence and key flag */
11331a66a836SWilliam Tu 	if (data[IFLA_GRE_OFLAGS])
113484e54fe0SWilliam Tu 		flags |= nla_get_be16(data[IFLA_GRE_OFLAGS]);
11351a66a836SWilliam Tu 	if (data[IFLA_GRE_IFLAGS])
113684e54fe0SWilliam Tu 		flags |= nla_get_be16(data[IFLA_GRE_IFLAGS]);
11371a66a836SWilliam Tu 	if (!data[IFLA_GRE_COLLECT_METADATA] &&
11381a66a836SWilliam Tu 	    flags != (GRE_SEQ | GRE_KEY))
113984e54fe0SWilliam Tu 		return -EINVAL;
114084e54fe0SWilliam Tu 
114184e54fe0SWilliam Tu 	/* ERSPAN Session ID only has 10-bit. Since we reuse
114284e54fe0SWilliam Tu 	 * 32-bit key field as ID, check it's range.
114384e54fe0SWilliam Tu 	 */
114484e54fe0SWilliam Tu 	if (data[IFLA_GRE_IKEY] &&
114584e54fe0SWilliam Tu 	    (ntohl(nla_get_be32(data[IFLA_GRE_IKEY])) & ~ID_MASK))
114684e54fe0SWilliam Tu 		return -EINVAL;
114784e54fe0SWilliam Tu 
114884e54fe0SWilliam Tu 	if (data[IFLA_GRE_OKEY] &&
114984e54fe0SWilliam Tu 	    (ntohl(nla_get_be32(data[IFLA_GRE_OKEY])) & ~ID_MASK))
115084e54fe0SWilliam Tu 		return -EINVAL;
115184e54fe0SWilliam Tu 
115284e54fe0SWilliam Tu 	return 0;
115384e54fe0SWilliam Tu }
115484e54fe0SWilliam Tu 
115522a59be8SPhilip Prindeville static int ipgre_netlink_parms(struct net_device *dev,
11562e15ea39SPravin B Shelar 				struct nlattr *data[],
11572e15ea39SPravin B Shelar 				struct nlattr *tb[],
11589830ad4cSCraig Gallek 				struct ip_tunnel_parm *parms,
11599830ad4cSCraig Gallek 				__u32 *fwmark)
1160c19e654dSHerbert Xu {
116122a59be8SPhilip Prindeville 	struct ip_tunnel *t = netdev_priv(dev);
116222a59be8SPhilip Prindeville 
11637bb82d92SHerbert Xu 	memset(parms, 0, sizeof(*parms));
1164c19e654dSHerbert Xu 
1165c19e654dSHerbert Xu 	parms->iph.protocol = IPPROTO_GRE;
1166c19e654dSHerbert Xu 
1167c19e654dSHerbert Xu 	if (!data)
116822a59be8SPhilip Prindeville 		return 0;
1169c19e654dSHerbert Xu 
1170c19e654dSHerbert Xu 	if (data[IFLA_GRE_LINK])
1171c19e654dSHerbert Xu 		parms->link = nla_get_u32(data[IFLA_GRE_LINK]);
1172c19e654dSHerbert Xu 
1173c19e654dSHerbert Xu 	if (data[IFLA_GRE_IFLAGS])
1174c5441932SPravin B Shelar 		parms->i_flags = gre_flags_to_tnl_flags(nla_get_be16(data[IFLA_GRE_IFLAGS]));
1175c19e654dSHerbert Xu 
1176c19e654dSHerbert Xu 	if (data[IFLA_GRE_OFLAGS])
1177c5441932SPravin B Shelar 		parms->o_flags = gre_flags_to_tnl_flags(nla_get_be16(data[IFLA_GRE_OFLAGS]));
1178c19e654dSHerbert Xu 
1179c19e654dSHerbert Xu 	if (data[IFLA_GRE_IKEY])
1180c19e654dSHerbert Xu 		parms->i_key = nla_get_be32(data[IFLA_GRE_IKEY]);
1181c19e654dSHerbert Xu 
1182c19e654dSHerbert Xu 	if (data[IFLA_GRE_OKEY])
1183c19e654dSHerbert Xu 		parms->o_key = nla_get_be32(data[IFLA_GRE_OKEY]);
1184c19e654dSHerbert Xu 
1185c19e654dSHerbert Xu 	if (data[IFLA_GRE_LOCAL])
118667b61f6cSJiri Benc 		parms->iph.saddr = nla_get_in_addr(data[IFLA_GRE_LOCAL]);
1187c19e654dSHerbert Xu 
1188c19e654dSHerbert Xu 	if (data[IFLA_GRE_REMOTE])
118967b61f6cSJiri Benc 		parms->iph.daddr = nla_get_in_addr(data[IFLA_GRE_REMOTE]);
1190c19e654dSHerbert Xu 
1191c19e654dSHerbert Xu 	if (data[IFLA_GRE_TTL])
1192c19e654dSHerbert Xu 		parms->iph.ttl = nla_get_u8(data[IFLA_GRE_TTL]);
1193c19e654dSHerbert Xu 
1194c19e654dSHerbert Xu 	if (data[IFLA_GRE_TOS])
1195c19e654dSHerbert Xu 		parms->iph.tos = nla_get_u8(data[IFLA_GRE_TOS]);
1196c19e654dSHerbert Xu 
119722a59be8SPhilip Prindeville 	if (!data[IFLA_GRE_PMTUDISC] || nla_get_u8(data[IFLA_GRE_PMTUDISC])) {
119822a59be8SPhilip Prindeville 		if (t->ignore_df)
119922a59be8SPhilip Prindeville 			return -EINVAL;
1200c19e654dSHerbert Xu 		parms->iph.frag_off = htons(IP_DF);
120122a59be8SPhilip Prindeville 	}
12022e15ea39SPravin B Shelar 
12032e15ea39SPravin B Shelar 	if (data[IFLA_GRE_COLLECT_METADATA]) {
12042e15ea39SPravin B Shelar 		t->collect_md = true;
1205e271c7b4SJiri Benc 		if (dev->type == ARPHRD_IPGRE)
1206e271c7b4SJiri Benc 			dev->type = ARPHRD_NONE;
12072e15ea39SPravin B Shelar 	}
120822a59be8SPhilip Prindeville 
120922a59be8SPhilip Prindeville 	if (data[IFLA_GRE_IGNORE_DF]) {
121022a59be8SPhilip Prindeville 		if (nla_get_u8(data[IFLA_GRE_IGNORE_DF])
121122a59be8SPhilip Prindeville 		  && (parms->iph.frag_off & htons(IP_DF)))
121222a59be8SPhilip Prindeville 			return -EINVAL;
121322a59be8SPhilip Prindeville 		t->ignore_df = !!nla_get_u8(data[IFLA_GRE_IGNORE_DF]);
121422a59be8SPhilip Prindeville 	}
121522a59be8SPhilip Prindeville 
12169830ad4cSCraig Gallek 	if (data[IFLA_GRE_FWMARK])
12179830ad4cSCraig Gallek 		*fwmark = nla_get_u32(data[IFLA_GRE_FWMARK]);
12189830ad4cSCraig Gallek 
1219f551c91dSWilliam Tu 	if (data[IFLA_GRE_ERSPAN_VER]) {
1220f551c91dSWilliam Tu 		t->erspan_ver = nla_get_u8(data[IFLA_GRE_ERSPAN_VER]);
1221f551c91dSWilliam Tu 
1222f551c91dSWilliam Tu 		if (t->erspan_ver != 1 && t->erspan_ver != 2)
1223f551c91dSWilliam Tu 			return -EINVAL;
1224f551c91dSWilliam Tu 	}
1225f551c91dSWilliam Tu 
1226f551c91dSWilliam Tu 	if (t->erspan_ver == 1) {
122784e54fe0SWilliam Tu 		if (data[IFLA_GRE_ERSPAN_INDEX]) {
122884e54fe0SWilliam Tu 			t->index = nla_get_u32(data[IFLA_GRE_ERSPAN_INDEX]);
122984e54fe0SWilliam Tu 			if (t->index & ~INDEX_MASK)
123084e54fe0SWilliam Tu 				return -EINVAL;
123184e54fe0SWilliam Tu 		}
1232f551c91dSWilliam Tu 	} else if (t->erspan_ver == 2) {
1233f551c91dSWilliam Tu 		if (data[IFLA_GRE_ERSPAN_DIR]) {
1234f551c91dSWilliam Tu 			t->dir = nla_get_u8(data[IFLA_GRE_ERSPAN_DIR]);
1235f551c91dSWilliam Tu 			if (t->dir & ~(DIR_MASK >> DIR_OFFSET))
1236f551c91dSWilliam Tu 				return -EINVAL;
1237f551c91dSWilliam Tu 		}
1238f551c91dSWilliam Tu 		if (data[IFLA_GRE_ERSPAN_HWID]) {
1239f551c91dSWilliam Tu 			t->hwid = nla_get_u16(data[IFLA_GRE_ERSPAN_HWID]);
1240f551c91dSWilliam Tu 			if (t->hwid & ~(HWID_MASK >> HWID_OFFSET))
1241f551c91dSWilliam Tu 				return -EINVAL;
1242f551c91dSWilliam Tu 		}
1243f551c91dSWilliam Tu 	}
124484e54fe0SWilliam Tu 
124522a59be8SPhilip Prindeville 	return 0;
1246c19e654dSHerbert Xu }
1247c19e654dSHerbert Xu 
12484565e991STom Herbert /* This function returns true when ENCAP attributes are present in the nl msg */
12494565e991STom Herbert static bool ipgre_netlink_encap_parms(struct nlattr *data[],
12504565e991STom Herbert 				      struct ip_tunnel_encap *ipencap)
12514565e991STom Herbert {
12524565e991STom Herbert 	bool ret = false;
12534565e991STom Herbert 
12544565e991STom Herbert 	memset(ipencap, 0, sizeof(*ipencap));
12554565e991STom Herbert 
12564565e991STom Herbert 	if (!data)
12574565e991STom Herbert 		return ret;
12584565e991STom Herbert 
12594565e991STom Herbert 	if (data[IFLA_GRE_ENCAP_TYPE]) {
12604565e991STom Herbert 		ret = true;
12614565e991STom Herbert 		ipencap->type = nla_get_u16(data[IFLA_GRE_ENCAP_TYPE]);
12624565e991STom Herbert 	}
12634565e991STom Herbert 
12644565e991STom Herbert 	if (data[IFLA_GRE_ENCAP_FLAGS]) {
12654565e991STom Herbert 		ret = true;
12664565e991STom Herbert 		ipencap->flags = nla_get_u16(data[IFLA_GRE_ENCAP_FLAGS]);
12674565e991STom Herbert 	}
12684565e991STom Herbert 
12694565e991STom Herbert 	if (data[IFLA_GRE_ENCAP_SPORT]) {
12704565e991STom Herbert 		ret = true;
12713e97fa70SSabrina Dubroca 		ipencap->sport = nla_get_be16(data[IFLA_GRE_ENCAP_SPORT]);
12724565e991STom Herbert 	}
12734565e991STom Herbert 
12744565e991STom Herbert 	if (data[IFLA_GRE_ENCAP_DPORT]) {
12754565e991STom Herbert 		ret = true;
12763e97fa70SSabrina Dubroca 		ipencap->dport = nla_get_be16(data[IFLA_GRE_ENCAP_DPORT]);
12774565e991STom Herbert 	}
12784565e991STom Herbert 
12794565e991STom Herbert 	return ret;
12804565e991STom Herbert }
12814565e991STom Herbert 
1282c5441932SPravin B Shelar static int gre_tap_init(struct net_device *dev)
1283e1a80002SHerbert Xu {
1284c5441932SPravin B Shelar 	__gre_tunnel_init(dev);
1285bec94d43Sstephen hemminger 	dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
1286d51711c0SXin Long 	netif_keep_dst(dev);
1287e1a80002SHerbert Xu 
1288c5441932SPravin B Shelar 	return ip_tunnel_init(dev);
1289e1a80002SHerbert Xu }
1290e1a80002SHerbert Xu 
1291c5441932SPravin B Shelar static const struct net_device_ops gre_tap_netdev_ops = {
1292c5441932SPravin B Shelar 	.ndo_init		= gre_tap_init,
1293c5441932SPravin B Shelar 	.ndo_uninit		= ip_tunnel_uninit,
1294c5441932SPravin B Shelar 	.ndo_start_xmit		= gre_tap_xmit,
1295b8c26a33SStephen Hemminger 	.ndo_set_mac_address 	= eth_mac_addr,
1296b8c26a33SStephen Hemminger 	.ndo_validate_addr	= eth_validate_addr,
1297c5441932SPravin B Shelar 	.ndo_change_mtu		= ip_tunnel_change_mtu,
1298c5441932SPravin B Shelar 	.ndo_get_stats64	= ip_tunnel_get_stats64,
12991e99584bSNicolas Dichtel 	.ndo_get_iflink		= ip_tunnel_get_iflink,
1300fc4099f1SPravin B Shelar 	.ndo_fill_metadata_dst	= gre_fill_metadata_dst,
1301b8c26a33SStephen Hemminger };
1302b8c26a33SStephen Hemminger 
130384e54fe0SWilliam Tu static int erspan_tunnel_init(struct net_device *dev)
130484e54fe0SWilliam Tu {
130584e54fe0SWilliam Tu 	struct ip_tunnel *tunnel = netdev_priv(dev);
130684e54fe0SWilliam Tu 
130784e54fe0SWilliam Tu 	tunnel->tun_hlen = 8;
130884e54fe0SWilliam Tu 	tunnel->parms.iph.protocol = IPPROTO_GRE;
1309c122fda2SXin Long 	tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen +
1310f551c91dSWilliam Tu 		       erspan_hdr_len(tunnel->erspan_ver);
131184e54fe0SWilliam Tu 
131284e54fe0SWilliam Tu 	dev->features		|= GRE_FEATURES;
131384e54fe0SWilliam Tu 	dev->hw_features	|= GRE_FEATURES;
131484e54fe0SWilliam Tu 	dev->priv_flags		|= IFF_LIVE_ADDR_CHANGE;
1315c84bed44SXin Long 	netif_keep_dst(dev);
131684e54fe0SWilliam Tu 
131784e54fe0SWilliam Tu 	return ip_tunnel_init(dev);
131884e54fe0SWilliam Tu }
131984e54fe0SWilliam Tu 
132084e54fe0SWilliam Tu static const struct net_device_ops erspan_netdev_ops = {
132184e54fe0SWilliam Tu 	.ndo_init		= erspan_tunnel_init,
132284e54fe0SWilliam Tu 	.ndo_uninit		= ip_tunnel_uninit,
132384e54fe0SWilliam Tu 	.ndo_start_xmit		= erspan_xmit,
132484e54fe0SWilliam Tu 	.ndo_set_mac_address	= eth_mac_addr,
132584e54fe0SWilliam Tu 	.ndo_validate_addr	= eth_validate_addr,
132684e54fe0SWilliam Tu 	.ndo_change_mtu		= ip_tunnel_change_mtu,
132784e54fe0SWilliam Tu 	.ndo_get_stats64	= ip_tunnel_get_stats64,
132884e54fe0SWilliam Tu 	.ndo_get_iflink		= ip_tunnel_get_iflink,
132984e54fe0SWilliam Tu 	.ndo_fill_metadata_dst	= gre_fill_metadata_dst,
133084e54fe0SWilliam Tu };
133184e54fe0SWilliam Tu 
1332e1a80002SHerbert Xu static void ipgre_tap_setup(struct net_device *dev)
1333e1a80002SHerbert Xu {
1334e1a80002SHerbert Xu 	ether_setup(dev);
1335cfddd4c3SXin Long 	dev->max_mtu = 0;
1336c5441932SPravin B Shelar 	dev->netdev_ops	= &gre_tap_netdev_ops;
1337d13b161cSJiri Benc 	dev->priv_flags &= ~IFF_TX_SKB_SHARING;
1338f8c1b7ceSstephen hemminger 	dev->priv_flags	|= IFF_LIVE_ADDR_CHANGE;
1339c5441932SPravin B Shelar 	ip_tunnel_setup(dev, gre_tap_net_id);
1340e1a80002SHerbert Xu }
1341e1a80002SHerbert Xu 
1342d1b2a6c4SPetr Machata bool is_gretap_dev(const struct net_device *dev)
1343d1b2a6c4SPetr Machata {
1344d1b2a6c4SPetr Machata 	return dev->netdev_ops == &gre_tap_netdev_ops;
1345d1b2a6c4SPetr Machata }
1346d1b2a6c4SPetr Machata EXPORT_SYMBOL_GPL(is_gretap_dev);
1347d1b2a6c4SPetr Machata 
1348c5441932SPravin B Shelar static int ipgre_newlink(struct net *src_net, struct net_device *dev,
13497a3f4a18SMatthias Schiffer 			 struct nlattr *tb[], struct nlattr *data[],
13507a3f4a18SMatthias Schiffer 			 struct netlink_ext_ack *extack)
1351c19e654dSHerbert Xu {
1352c5441932SPravin B Shelar 	struct ip_tunnel_parm p;
13534565e991STom Herbert 	struct ip_tunnel_encap ipencap;
13549830ad4cSCraig Gallek 	__u32 fwmark = 0;
135522a59be8SPhilip Prindeville 	int err;
13564565e991STom Herbert 
13574565e991STom Herbert 	if (ipgre_netlink_encap_parms(data, &ipencap)) {
13584565e991STom Herbert 		struct ip_tunnel *t = netdev_priv(dev);
135922a59be8SPhilip Prindeville 		err = ip_tunnel_encap_setup(t, &ipencap);
13604565e991STom Herbert 
13614565e991STom Herbert 		if (err < 0)
13624565e991STom Herbert 			return err;
13634565e991STom Herbert 	}
1364c19e654dSHerbert Xu 
13659830ad4cSCraig Gallek 	err = ipgre_netlink_parms(dev, data, tb, &p, &fwmark);
136622a59be8SPhilip Prindeville 	if (err < 0)
136722a59be8SPhilip Prindeville 		return err;
13689830ad4cSCraig Gallek 	return ip_tunnel_newlink(dev, tb, &p, fwmark);
1369c19e654dSHerbert Xu }
1370c19e654dSHerbert Xu 
1371c19e654dSHerbert Xu static int ipgre_changelink(struct net_device *dev, struct nlattr *tb[],
1372ad744b22SMatthias Schiffer 			    struct nlattr *data[],
1373ad744b22SMatthias Schiffer 			    struct netlink_ext_ack *extack)
1374c19e654dSHerbert Xu {
13759830ad4cSCraig Gallek 	struct ip_tunnel *t = netdev_priv(dev);
13764565e991STom Herbert 	struct ip_tunnel_encap ipencap;
13779830ad4cSCraig Gallek 	__u32 fwmark = t->fwmark;
1378dd9d598cSXin Long 	struct ip_tunnel_parm p;
137922a59be8SPhilip Prindeville 	int err;
13804565e991STom Herbert 
13814565e991STom Herbert 	if (ipgre_netlink_encap_parms(data, &ipencap)) {
138222a59be8SPhilip Prindeville 		err = ip_tunnel_encap_setup(t, &ipencap);
13834565e991STom Herbert 
13844565e991STom Herbert 		if (err < 0)
13854565e991STom Herbert 			return err;
13864565e991STom Herbert 	}
1387c19e654dSHerbert Xu 
13889830ad4cSCraig Gallek 	err = ipgre_netlink_parms(dev, data, tb, &p, &fwmark);
138922a59be8SPhilip Prindeville 	if (err < 0)
139022a59be8SPhilip Prindeville 		return err;
1391dd9d598cSXin Long 
1392dd9d598cSXin Long 	err = ip_tunnel_changelink(dev, tb, &p, fwmark);
1393dd9d598cSXin Long 	if (err < 0)
1394dd9d598cSXin Long 		return err;
1395dd9d598cSXin Long 
1396dd9d598cSXin Long 	t->parms.i_flags = p.i_flags;
1397dd9d598cSXin Long 	t->parms.o_flags = p.o_flags;
1398dd9d598cSXin Long 
1399dd9d598cSXin Long 	if (strcmp(dev->rtnl_link_ops->kind, "erspan"))
1400dd9d598cSXin Long 		ipgre_link_update(dev, !tb[IFLA_MTU]);
1401dd9d598cSXin Long 
1402dd9d598cSXin Long 	return 0;
1403c19e654dSHerbert Xu }
1404c19e654dSHerbert Xu 
1405c19e654dSHerbert Xu static size_t ipgre_get_size(const struct net_device *dev)
1406c19e654dSHerbert Xu {
1407c19e654dSHerbert Xu 	return
1408c19e654dSHerbert Xu 		/* IFLA_GRE_LINK */
1409c19e654dSHerbert Xu 		nla_total_size(4) +
1410c19e654dSHerbert Xu 		/* IFLA_GRE_IFLAGS */
1411c19e654dSHerbert Xu 		nla_total_size(2) +
1412c19e654dSHerbert Xu 		/* IFLA_GRE_OFLAGS */
1413c19e654dSHerbert Xu 		nla_total_size(2) +
1414c19e654dSHerbert Xu 		/* IFLA_GRE_IKEY */
1415c19e654dSHerbert Xu 		nla_total_size(4) +
1416c19e654dSHerbert Xu 		/* IFLA_GRE_OKEY */
1417c19e654dSHerbert Xu 		nla_total_size(4) +
1418c19e654dSHerbert Xu 		/* IFLA_GRE_LOCAL */
1419c19e654dSHerbert Xu 		nla_total_size(4) +
1420c19e654dSHerbert Xu 		/* IFLA_GRE_REMOTE */
1421c19e654dSHerbert Xu 		nla_total_size(4) +
1422c19e654dSHerbert Xu 		/* IFLA_GRE_TTL */
1423c19e654dSHerbert Xu 		nla_total_size(1) +
1424c19e654dSHerbert Xu 		/* IFLA_GRE_TOS */
1425c19e654dSHerbert Xu 		nla_total_size(1) +
1426c19e654dSHerbert Xu 		/* IFLA_GRE_PMTUDISC */
1427c19e654dSHerbert Xu 		nla_total_size(1) +
14284565e991STom Herbert 		/* IFLA_GRE_ENCAP_TYPE */
14294565e991STom Herbert 		nla_total_size(2) +
14304565e991STom Herbert 		/* IFLA_GRE_ENCAP_FLAGS */
14314565e991STom Herbert 		nla_total_size(2) +
14324565e991STom Herbert 		/* IFLA_GRE_ENCAP_SPORT */
14334565e991STom Herbert 		nla_total_size(2) +
14344565e991STom Herbert 		/* IFLA_GRE_ENCAP_DPORT */
14354565e991STom Herbert 		nla_total_size(2) +
14362e15ea39SPravin B Shelar 		/* IFLA_GRE_COLLECT_METADATA */
14372e15ea39SPravin B Shelar 		nla_total_size(0) +
143822a59be8SPhilip Prindeville 		/* IFLA_GRE_IGNORE_DF */
143922a59be8SPhilip Prindeville 		nla_total_size(1) +
14409830ad4cSCraig Gallek 		/* IFLA_GRE_FWMARK */
14419830ad4cSCraig Gallek 		nla_total_size(4) +
144284e54fe0SWilliam Tu 		/* IFLA_GRE_ERSPAN_INDEX */
144384e54fe0SWilliam Tu 		nla_total_size(4) +
1444f551c91dSWilliam Tu 		/* IFLA_GRE_ERSPAN_VER */
1445f551c91dSWilliam Tu 		nla_total_size(1) +
1446f551c91dSWilliam Tu 		/* IFLA_GRE_ERSPAN_DIR */
1447f551c91dSWilliam Tu 		nla_total_size(1) +
1448f551c91dSWilliam Tu 		/* IFLA_GRE_ERSPAN_HWID */
1449f551c91dSWilliam Tu 		nla_total_size(2) +
1450c19e654dSHerbert Xu 		0;
1451c19e654dSHerbert Xu }
1452c19e654dSHerbert Xu 
1453c19e654dSHerbert Xu static int ipgre_fill_info(struct sk_buff *skb, const struct net_device *dev)
1454c19e654dSHerbert Xu {
1455c19e654dSHerbert Xu 	struct ip_tunnel *t = netdev_priv(dev);
1456c19e654dSHerbert Xu 	struct ip_tunnel_parm *p = &t->parms;
1457c19e654dSHerbert Xu 
1458f3756b79SDavid S. Miller 	if (nla_put_u32(skb, IFLA_GRE_LINK, p->link) ||
145995f5c64cSTom Herbert 	    nla_put_be16(skb, IFLA_GRE_IFLAGS,
146095f5c64cSTom Herbert 			 gre_tnl_flags_to_gre_flags(p->i_flags)) ||
146195f5c64cSTom Herbert 	    nla_put_be16(skb, IFLA_GRE_OFLAGS,
146295f5c64cSTom Herbert 			 gre_tnl_flags_to_gre_flags(p->o_flags)) ||
1463f3756b79SDavid S. Miller 	    nla_put_be32(skb, IFLA_GRE_IKEY, p->i_key) ||
1464f3756b79SDavid S. Miller 	    nla_put_be32(skb, IFLA_GRE_OKEY, p->o_key) ||
1465930345eaSJiri Benc 	    nla_put_in_addr(skb, IFLA_GRE_LOCAL, p->iph.saddr) ||
1466930345eaSJiri Benc 	    nla_put_in_addr(skb, IFLA_GRE_REMOTE, p->iph.daddr) ||
1467f3756b79SDavid S. Miller 	    nla_put_u8(skb, IFLA_GRE_TTL, p->iph.ttl) ||
1468f3756b79SDavid S. Miller 	    nla_put_u8(skb, IFLA_GRE_TOS, p->iph.tos) ||
1469f3756b79SDavid S. Miller 	    nla_put_u8(skb, IFLA_GRE_PMTUDISC,
14709830ad4cSCraig Gallek 		       !!(p->iph.frag_off & htons(IP_DF))) ||
14719830ad4cSCraig Gallek 	    nla_put_u32(skb, IFLA_GRE_FWMARK, t->fwmark))
1472f3756b79SDavid S. Miller 		goto nla_put_failure;
14734565e991STom Herbert 
14744565e991STom Herbert 	if (nla_put_u16(skb, IFLA_GRE_ENCAP_TYPE,
14754565e991STom Herbert 			t->encap.type) ||
14763e97fa70SSabrina Dubroca 	    nla_put_be16(skb, IFLA_GRE_ENCAP_SPORT,
14774565e991STom Herbert 			 t->encap.sport) ||
14783e97fa70SSabrina Dubroca 	    nla_put_be16(skb, IFLA_GRE_ENCAP_DPORT,
14794565e991STom Herbert 			 t->encap.dport) ||
14804565e991STom Herbert 	    nla_put_u16(skb, IFLA_GRE_ENCAP_FLAGS,
1481e1b2cb65STom Herbert 			t->encap.flags))
14824565e991STom Herbert 		goto nla_put_failure;
14834565e991STom Herbert 
148422a59be8SPhilip Prindeville 	if (nla_put_u8(skb, IFLA_GRE_IGNORE_DF, t->ignore_df))
148522a59be8SPhilip Prindeville 		goto nla_put_failure;
148622a59be8SPhilip Prindeville 
14872e15ea39SPravin B Shelar 	if (t->collect_md) {
14882e15ea39SPravin B Shelar 		if (nla_put_flag(skb, IFLA_GRE_COLLECT_METADATA))
14892e15ea39SPravin B Shelar 			goto nla_put_failure;
14902e15ea39SPravin B Shelar 	}
14912e15ea39SPravin B Shelar 
1492f551c91dSWilliam Tu 	if (nla_put_u8(skb, IFLA_GRE_ERSPAN_VER, t->erspan_ver))
1493f551c91dSWilliam Tu 		goto nla_put_failure;
1494f551c91dSWilliam Tu 
1495f551c91dSWilliam Tu 	if (t->erspan_ver == 1) {
149684e54fe0SWilliam Tu 		if (nla_put_u32(skb, IFLA_GRE_ERSPAN_INDEX, t->index))
149784e54fe0SWilliam Tu 			goto nla_put_failure;
1498f551c91dSWilliam Tu 	} else if (t->erspan_ver == 2) {
1499f551c91dSWilliam Tu 		if (nla_put_u8(skb, IFLA_GRE_ERSPAN_DIR, t->dir))
1500f551c91dSWilliam Tu 			goto nla_put_failure;
1501f551c91dSWilliam Tu 		if (nla_put_u16(skb, IFLA_GRE_ERSPAN_HWID, t->hwid))
1502f551c91dSWilliam Tu 			goto nla_put_failure;
1503f551c91dSWilliam Tu 	}
150484e54fe0SWilliam Tu 
1505c19e654dSHerbert Xu 	return 0;
1506c19e654dSHerbert Xu 
1507c19e654dSHerbert Xu nla_put_failure:
1508c19e654dSHerbert Xu 	return -EMSGSIZE;
1509c19e654dSHerbert Xu }
1510c19e654dSHerbert Xu 
151184e54fe0SWilliam Tu static void erspan_setup(struct net_device *dev)
151284e54fe0SWilliam Tu {
151384581bdaSXin Long 	struct ip_tunnel *t = netdev_priv(dev);
151484581bdaSXin Long 
151584e54fe0SWilliam Tu 	ether_setup(dev);
151684e54fe0SWilliam Tu 	dev->netdev_ops = &erspan_netdev_ops;
151784e54fe0SWilliam Tu 	dev->priv_flags &= ~IFF_TX_SKB_SHARING;
151884e54fe0SWilliam Tu 	dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
151984e54fe0SWilliam Tu 	ip_tunnel_setup(dev, erspan_net_id);
152084581bdaSXin Long 	t->erspan_ver = 1;
152184e54fe0SWilliam Tu }
152284e54fe0SWilliam Tu 
1523c19e654dSHerbert Xu static const struct nla_policy ipgre_policy[IFLA_GRE_MAX + 1] = {
1524c19e654dSHerbert Xu 	[IFLA_GRE_LINK]		= { .type = NLA_U32 },
1525c19e654dSHerbert Xu 	[IFLA_GRE_IFLAGS]	= { .type = NLA_U16 },
1526c19e654dSHerbert Xu 	[IFLA_GRE_OFLAGS]	= { .type = NLA_U16 },
1527c19e654dSHerbert Xu 	[IFLA_GRE_IKEY]		= { .type = NLA_U32 },
1528c19e654dSHerbert Xu 	[IFLA_GRE_OKEY]		= { .type = NLA_U32 },
15294d74f8baSPatrick McHardy 	[IFLA_GRE_LOCAL]	= { .len = FIELD_SIZEOF(struct iphdr, saddr) },
15304d74f8baSPatrick McHardy 	[IFLA_GRE_REMOTE]	= { .len = FIELD_SIZEOF(struct iphdr, daddr) },
1531c19e654dSHerbert Xu 	[IFLA_GRE_TTL]		= { .type = NLA_U8 },
1532c19e654dSHerbert Xu 	[IFLA_GRE_TOS]		= { .type = NLA_U8 },
1533c19e654dSHerbert Xu 	[IFLA_GRE_PMTUDISC]	= { .type = NLA_U8 },
15344565e991STom Herbert 	[IFLA_GRE_ENCAP_TYPE]	= { .type = NLA_U16 },
15354565e991STom Herbert 	[IFLA_GRE_ENCAP_FLAGS]	= { .type = NLA_U16 },
15364565e991STom Herbert 	[IFLA_GRE_ENCAP_SPORT]	= { .type = NLA_U16 },
15374565e991STom Herbert 	[IFLA_GRE_ENCAP_DPORT]	= { .type = NLA_U16 },
15382e15ea39SPravin B Shelar 	[IFLA_GRE_COLLECT_METADATA]	= { .type = NLA_FLAG },
153922a59be8SPhilip Prindeville 	[IFLA_GRE_IGNORE_DF]	= { .type = NLA_U8 },
15409830ad4cSCraig Gallek 	[IFLA_GRE_FWMARK]	= { .type = NLA_U32 },
154184e54fe0SWilliam Tu 	[IFLA_GRE_ERSPAN_INDEX]	= { .type = NLA_U32 },
1542f551c91dSWilliam Tu 	[IFLA_GRE_ERSPAN_VER]	= { .type = NLA_U8 },
1543f551c91dSWilliam Tu 	[IFLA_GRE_ERSPAN_DIR]	= { .type = NLA_U8 },
1544f551c91dSWilliam Tu 	[IFLA_GRE_ERSPAN_HWID]	= { .type = NLA_U16 },
1545c19e654dSHerbert Xu };
1546c19e654dSHerbert Xu 
1547c19e654dSHerbert Xu static struct rtnl_link_ops ipgre_link_ops __read_mostly = {
1548c19e654dSHerbert Xu 	.kind		= "gre",
1549c19e654dSHerbert Xu 	.maxtype	= IFLA_GRE_MAX,
1550c19e654dSHerbert Xu 	.policy		= ipgre_policy,
1551c19e654dSHerbert Xu 	.priv_size	= sizeof(struct ip_tunnel),
1552c19e654dSHerbert Xu 	.setup		= ipgre_tunnel_setup,
1553c19e654dSHerbert Xu 	.validate	= ipgre_tunnel_validate,
1554c19e654dSHerbert Xu 	.newlink	= ipgre_newlink,
1555c19e654dSHerbert Xu 	.changelink	= ipgre_changelink,
1556c5441932SPravin B Shelar 	.dellink	= ip_tunnel_dellink,
1557c19e654dSHerbert Xu 	.get_size	= ipgre_get_size,
1558c19e654dSHerbert Xu 	.fill_info	= ipgre_fill_info,
15591728d4faSNicolas Dichtel 	.get_link_net	= ip_tunnel_get_link_net,
1560c19e654dSHerbert Xu };
1561c19e654dSHerbert Xu 
1562e1a80002SHerbert Xu static struct rtnl_link_ops ipgre_tap_ops __read_mostly = {
1563e1a80002SHerbert Xu 	.kind		= "gretap",
1564e1a80002SHerbert Xu 	.maxtype	= IFLA_GRE_MAX,
1565e1a80002SHerbert Xu 	.policy		= ipgre_policy,
1566e1a80002SHerbert Xu 	.priv_size	= sizeof(struct ip_tunnel),
1567e1a80002SHerbert Xu 	.setup		= ipgre_tap_setup,
1568e1a80002SHerbert Xu 	.validate	= ipgre_tap_validate,
1569e1a80002SHerbert Xu 	.newlink	= ipgre_newlink,
1570e1a80002SHerbert Xu 	.changelink	= ipgre_changelink,
1571c5441932SPravin B Shelar 	.dellink	= ip_tunnel_dellink,
1572e1a80002SHerbert Xu 	.get_size	= ipgre_get_size,
1573e1a80002SHerbert Xu 	.fill_info	= ipgre_fill_info,
15741728d4faSNicolas Dichtel 	.get_link_net	= ip_tunnel_get_link_net,
1575e1a80002SHerbert Xu };
1576e1a80002SHerbert Xu 
157784e54fe0SWilliam Tu static struct rtnl_link_ops erspan_link_ops __read_mostly = {
157884e54fe0SWilliam Tu 	.kind		= "erspan",
157984e54fe0SWilliam Tu 	.maxtype	= IFLA_GRE_MAX,
158084e54fe0SWilliam Tu 	.policy		= ipgre_policy,
158184e54fe0SWilliam Tu 	.priv_size	= sizeof(struct ip_tunnel),
158284e54fe0SWilliam Tu 	.setup		= erspan_setup,
158384e54fe0SWilliam Tu 	.validate	= erspan_validate,
158484e54fe0SWilliam Tu 	.newlink	= ipgre_newlink,
158584e54fe0SWilliam Tu 	.changelink	= ipgre_changelink,
158684e54fe0SWilliam Tu 	.dellink	= ip_tunnel_dellink,
158784e54fe0SWilliam Tu 	.get_size	= ipgre_get_size,
158884e54fe0SWilliam Tu 	.fill_info	= ipgre_fill_info,
158984e54fe0SWilliam Tu 	.get_link_net	= ip_tunnel_get_link_net,
159084e54fe0SWilliam Tu };
159184e54fe0SWilliam Tu 
1592b2acd1dcSPravin B Shelar struct net_device *gretap_fb_dev_create(struct net *net, const char *name,
1593b2acd1dcSPravin B Shelar 					u8 name_assign_type)
1594b2acd1dcSPravin B Shelar {
1595b2acd1dcSPravin B Shelar 	struct nlattr *tb[IFLA_MAX + 1];
1596b2acd1dcSPravin B Shelar 	struct net_device *dev;
1597106da663SNicolas Dichtel 	LIST_HEAD(list_kill);
1598b2acd1dcSPravin B Shelar 	struct ip_tunnel *t;
1599b2acd1dcSPravin B Shelar 	int err;
1600b2acd1dcSPravin B Shelar 
1601b2acd1dcSPravin B Shelar 	memset(&tb, 0, sizeof(tb));
1602b2acd1dcSPravin B Shelar 
1603b2acd1dcSPravin B Shelar 	dev = rtnl_create_link(net, name, name_assign_type,
1604*d0522f1cSDavid Ahern 			       &ipgre_tap_ops, tb, NULL);
1605b2acd1dcSPravin B Shelar 	if (IS_ERR(dev))
1606b2acd1dcSPravin B Shelar 		return dev;
1607b2acd1dcSPravin B Shelar 
1608b2acd1dcSPravin B Shelar 	/* Configure flow based GRE device. */
1609b2acd1dcSPravin B Shelar 	t = netdev_priv(dev);
1610b2acd1dcSPravin B Shelar 	t->collect_md = true;
1611b2acd1dcSPravin B Shelar 
16127a3f4a18SMatthias Schiffer 	err = ipgre_newlink(net, dev, tb, NULL, NULL);
1613106da663SNicolas Dichtel 	if (err < 0) {
1614106da663SNicolas Dichtel 		free_netdev(dev);
1615106da663SNicolas Dichtel 		return ERR_PTR(err);
1616106da663SNicolas Dichtel 	}
16177e059158SDavid Wragg 
16187e059158SDavid Wragg 	/* openvswitch users expect packet sizes to be unrestricted,
16197e059158SDavid Wragg 	 * so set the largest MTU we can.
16207e059158SDavid Wragg 	 */
16217e059158SDavid Wragg 	err = __ip_tunnel_change_mtu(dev, IP_MAX_MTU, false);
16227e059158SDavid Wragg 	if (err)
16237e059158SDavid Wragg 		goto out;
16247e059158SDavid Wragg 
1625da6f1da8SNicolas Dichtel 	err = rtnl_configure_link(dev, NULL);
1626da6f1da8SNicolas Dichtel 	if (err < 0)
1627da6f1da8SNicolas Dichtel 		goto out;
1628da6f1da8SNicolas Dichtel 
1629b2acd1dcSPravin B Shelar 	return dev;
1630b2acd1dcSPravin B Shelar out:
1631106da663SNicolas Dichtel 	ip_tunnel_dellink(dev, &list_kill);
1632106da663SNicolas Dichtel 	unregister_netdevice_many(&list_kill);
1633b2acd1dcSPravin B Shelar 	return ERR_PTR(err);
1634b2acd1dcSPravin B Shelar }
1635b2acd1dcSPravin B Shelar EXPORT_SYMBOL_GPL(gretap_fb_dev_create);
1636b2acd1dcSPravin B Shelar 
1637c5441932SPravin B Shelar static int __net_init ipgre_tap_init_net(struct net *net)
1638c5441932SPravin B Shelar {
16392e15ea39SPravin B Shelar 	return ip_tunnel_init_net(net, gre_tap_net_id, &ipgre_tap_ops, "gretap0");
1640c5441932SPravin B Shelar }
1641c5441932SPravin B Shelar 
164264bc1781SEric Dumazet static void __net_exit ipgre_tap_exit_batch_net(struct list_head *list_net)
1643c5441932SPravin B Shelar {
164464bc1781SEric Dumazet 	ip_tunnel_delete_nets(list_net, gre_tap_net_id, &ipgre_tap_ops);
1645c5441932SPravin B Shelar }
1646c5441932SPravin B Shelar 
1647c5441932SPravin B Shelar static struct pernet_operations ipgre_tap_net_ops = {
1648c5441932SPravin B Shelar 	.init = ipgre_tap_init_net,
164964bc1781SEric Dumazet 	.exit_batch = ipgre_tap_exit_batch_net,
1650c5441932SPravin B Shelar 	.id   = &gre_tap_net_id,
1651c5441932SPravin B Shelar 	.size = sizeof(struct ip_tunnel_net),
1652c5441932SPravin B Shelar };
16531da177e4SLinus Torvalds 
165484e54fe0SWilliam Tu static int __net_init erspan_init_net(struct net *net)
165584e54fe0SWilliam Tu {
165684e54fe0SWilliam Tu 	return ip_tunnel_init_net(net, erspan_net_id,
165784e54fe0SWilliam Tu 				  &erspan_link_ops, "erspan0");
165884e54fe0SWilliam Tu }
165984e54fe0SWilliam Tu 
166064bc1781SEric Dumazet static void __net_exit erspan_exit_batch_net(struct list_head *net_list)
166184e54fe0SWilliam Tu {
166264bc1781SEric Dumazet 	ip_tunnel_delete_nets(net_list, erspan_net_id, &erspan_link_ops);
166384e54fe0SWilliam Tu }
166484e54fe0SWilliam Tu 
166584e54fe0SWilliam Tu static struct pernet_operations erspan_net_ops = {
166684e54fe0SWilliam Tu 	.init = erspan_init_net,
166764bc1781SEric Dumazet 	.exit_batch = erspan_exit_batch_net,
166884e54fe0SWilliam Tu 	.id   = &erspan_net_id,
166984e54fe0SWilliam Tu 	.size = sizeof(struct ip_tunnel_net),
167084e54fe0SWilliam Tu };
167184e54fe0SWilliam Tu 
16721da177e4SLinus Torvalds static int __init ipgre_init(void)
16731da177e4SLinus Torvalds {
16741da177e4SLinus Torvalds 	int err;
16751da177e4SLinus Torvalds 
1676058bd4d2SJoe Perches 	pr_info("GRE over IPv4 tunneling driver\n");
16771da177e4SLinus Torvalds 
1678cfb8fbf2SEric W. Biederman 	err = register_pernet_device(&ipgre_net_ops);
167959a4c759SPavel Emelyanov 	if (err < 0)
1680c2892f02SAlexey Dobriyan 		return err;
1681c2892f02SAlexey Dobriyan 
1682c5441932SPravin B Shelar 	err = register_pernet_device(&ipgre_tap_net_ops);
1683c5441932SPravin B Shelar 	if (err < 0)
1684e3d0328cSWilliam Tu 		goto pnet_tap_failed;
1685c5441932SPravin B Shelar 
168684e54fe0SWilliam Tu 	err = register_pernet_device(&erspan_net_ops);
168784e54fe0SWilliam Tu 	if (err < 0)
168884e54fe0SWilliam Tu 		goto pnet_erspan_failed;
168984e54fe0SWilliam Tu 
16909f57c67cSPravin B Shelar 	err = gre_add_protocol(&ipgre_protocol, GREPROTO_CISCO);
1691c2892f02SAlexey Dobriyan 	if (err < 0) {
1692058bd4d2SJoe Perches 		pr_info("%s: can't add protocol\n", __func__);
1693c2892f02SAlexey Dobriyan 		goto add_proto_failed;
1694c2892f02SAlexey Dobriyan 	}
16957daa0004SPavel Emelyanov 
1696c19e654dSHerbert Xu 	err = rtnl_link_register(&ipgre_link_ops);
1697c19e654dSHerbert Xu 	if (err < 0)
1698c19e654dSHerbert Xu 		goto rtnl_link_failed;
1699c19e654dSHerbert Xu 
1700e1a80002SHerbert Xu 	err = rtnl_link_register(&ipgre_tap_ops);
1701e1a80002SHerbert Xu 	if (err < 0)
1702e1a80002SHerbert Xu 		goto tap_ops_failed;
1703e1a80002SHerbert Xu 
170484e54fe0SWilliam Tu 	err = rtnl_link_register(&erspan_link_ops);
170584e54fe0SWilliam Tu 	if (err < 0)
170684e54fe0SWilliam Tu 		goto erspan_link_failed;
170784e54fe0SWilliam Tu 
1708c5441932SPravin B Shelar 	return 0;
1709c19e654dSHerbert Xu 
171084e54fe0SWilliam Tu erspan_link_failed:
171184e54fe0SWilliam Tu 	rtnl_link_unregister(&ipgre_tap_ops);
1712e1a80002SHerbert Xu tap_ops_failed:
1713e1a80002SHerbert Xu 	rtnl_link_unregister(&ipgre_link_ops);
1714c19e654dSHerbert Xu rtnl_link_failed:
17159f57c67cSPravin B Shelar 	gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO);
1716c2892f02SAlexey Dobriyan add_proto_failed:
171784e54fe0SWilliam Tu 	unregister_pernet_device(&erspan_net_ops);
171884e54fe0SWilliam Tu pnet_erspan_failed:
1719c5441932SPravin B Shelar 	unregister_pernet_device(&ipgre_tap_net_ops);
1720e3d0328cSWilliam Tu pnet_tap_failed:
1721c2892f02SAlexey Dobriyan 	unregister_pernet_device(&ipgre_net_ops);
1722c5441932SPravin B Shelar 	return err;
17231da177e4SLinus Torvalds }
17241da177e4SLinus Torvalds 
1725db44575fSAlexey Kuznetsov static void __exit ipgre_fini(void)
17261da177e4SLinus Torvalds {
1727e1a80002SHerbert Xu 	rtnl_link_unregister(&ipgre_tap_ops);
1728c19e654dSHerbert Xu 	rtnl_link_unregister(&ipgre_link_ops);
172984e54fe0SWilliam Tu 	rtnl_link_unregister(&erspan_link_ops);
17309f57c67cSPravin B Shelar 	gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO);
1731c5441932SPravin B Shelar 	unregister_pernet_device(&ipgre_tap_net_ops);
1732c2892f02SAlexey Dobriyan 	unregister_pernet_device(&ipgre_net_ops);
173384e54fe0SWilliam Tu 	unregister_pernet_device(&erspan_net_ops);
17341da177e4SLinus Torvalds }
17351da177e4SLinus Torvalds 
17361da177e4SLinus Torvalds module_init(ipgre_init);
17371da177e4SLinus Torvalds module_exit(ipgre_fini);
17381da177e4SLinus Torvalds MODULE_LICENSE("GPL");
17394d74f8baSPatrick McHardy MODULE_ALIAS_RTNL_LINK("gre");
17404d74f8baSPatrick McHardy MODULE_ALIAS_RTNL_LINK("gretap");
174184e54fe0SWilliam Tu MODULE_ALIAS_RTNL_LINK("erspan");
17428909c9adSVasiliy Kulikov MODULE_ALIAS_NETDEV("gre0");
1743c5441932SPravin B Shelar MODULE_ALIAS_NETDEV("gretap0");
174484e54fe0SWilliam Tu MODULE_ALIAS_NETDEV("erspan0");
1745