xref: /linux/net/ipv4/ip_gre.c (revision 51fa960d3b5163b1af22efdebcabfccc5d615ad6)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  *	Linux NET3:	GRE over IP protocol decoder.
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  *	Authors: Alexey Kuznetsov (kuznet@ms2.inr.ac.ru)
61da177e4SLinus Torvalds  */
71da177e4SLinus Torvalds 
8afd46503SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
9afd46503SJoe Perches 
104fc268d2SRandy Dunlap #include <linux/capability.h>
111da177e4SLinus Torvalds #include <linux/module.h>
121da177e4SLinus Torvalds #include <linux/types.h>
131da177e4SLinus Torvalds #include <linux/kernel.h>
145a0e3ad6STejun Heo #include <linux/slab.h>
157c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
161da177e4SLinus Torvalds #include <linux/skbuff.h>
171da177e4SLinus Torvalds #include <linux/netdevice.h>
181da177e4SLinus Torvalds #include <linux/in.h>
191da177e4SLinus Torvalds #include <linux/tcp.h>
201da177e4SLinus Torvalds #include <linux/udp.h>
211da177e4SLinus Torvalds #include <linux/if_arp.h>
222e15ea39SPravin B Shelar #include <linux/if_vlan.h>
231da177e4SLinus Torvalds #include <linux/init.h>
241da177e4SLinus Torvalds #include <linux/in6.h>
251da177e4SLinus Torvalds #include <linux/inetdevice.h>
261da177e4SLinus Torvalds #include <linux/igmp.h>
271da177e4SLinus Torvalds #include <linux/netfilter_ipv4.h>
28e1a80002SHerbert Xu #include <linux/etherdevice.h>
2946f25dffSKris Katterjohn #include <linux/if_ether.h>
301da177e4SLinus Torvalds 
311da177e4SLinus Torvalds #include <net/sock.h>
321da177e4SLinus Torvalds #include <net/ip.h>
331da177e4SLinus Torvalds #include <net/icmp.h>
341da177e4SLinus Torvalds #include <net/protocol.h>
35c5441932SPravin B Shelar #include <net/ip_tunnels.h>
361da177e4SLinus Torvalds #include <net/arp.h>
371da177e4SLinus Torvalds #include <net/checksum.h>
381da177e4SLinus Torvalds #include <net/dsfield.h>
391da177e4SLinus Torvalds #include <net/inet_ecn.h>
401da177e4SLinus Torvalds #include <net/xfrm.h>
4159a4c759SPavel Emelyanov #include <net/net_namespace.h>
4259a4c759SPavel Emelyanov #include <net/netns/generic.h>
43c19e654dSHerbert Xu #include <net/rtnetlink.h>
4400959adeSDmitry Kozlov #include <net/gre.h>
452e15ea39SPravin B Shelar #include <net/dst_metadata.h>
4684e54fe0SWilliam Tu #include <net/erspan.h>
471da177e4SLinus Torvalds 
481da177e4SLinus Torvalds /*
491da177e4SLinus Torvalds    Problems & solutions
501da177e4SLinus Torvalds    --------------------
511da177e4SLinus Torvalds 
521da177e4SLinus Torvalds    1. The most important issue is detecting local dead loops.
531da177e4SLinus Torvalds    They would cause complete host lockup in transmit, which
541da177e4SLinus Torvalds    would be "resolved" by stack overflow or, if queueing is enabled,
551da177e4SLinus Torvalds    with infinite looping in net_bh.
561da177e4SLinus Torvalds 
571da177e4SLinus Torvalds    We cannot track such dead loops during route installation,
581da177e4SLinus Torvalds    it is infeasible task. The most general solutions would be
591da177e4SLinus Torvalds    to keep skb->encapsulation counter (sort of local ttl),
606d0722a2SEric Dumazet    and silently drop packet when it expires. It is a good
61bff52857Sstephen hemminger    solution, but it supposes maintaining new variable in ALL
621da177e4SLinus Torvalds    skb, even if no tunneling is used.
631da177e4SLinus Torvalds 
646d0722a2SEric Dumazet    Current solution: xmit_recursion breaks dead loops. This is a percpu
656d0722a2SEric Dumazet    counter, since when we enter the first ndo_xmit(), cpu migration is
666d0722a2SEric Dumazet    forbidden. We force an exit if this counter reaches RECURSION_LIMIT
671da177e4SLinus Torvalds 
681da177e4SLinus Torvalds    2. Networking dead loops would not kill routers, but would really
691da177e4SLinus Torvalds    kill network. IP hop limit plays role of "t->recursion" in this case,
701da177e4SLinus Torvalds    if we copy it from packet being encapsulated to upper header.
711da177e4SLinus Torvalds    It is very good solution, but it introduces two problems:
721da177e4SLinus Torvalds 
731da177e4SLinus Torvalds    - Routing protocols, using packets with ttl=1 (OSPF, RIP2),
741da177e4SLinus Torvalds      do not work over tunnels.
751da177e4SLinus Torvalds    - traceroute does not work. I planned to relay ICMP from tunnel,
761da177e4SLinus Torvalds      so that this problem would be solved and traceroute output
771da177e4SLinus Torvalds      would even more informative. This idea appeared to be wrong:
781da177e4SLinus Torvalds      only Linux complies to rfc1812 now (yes, guys, Linux is the only
791da177e4SLinus Torvalds      true router now :-)), all routers (at least, in neighbourhood of mine)
801da177e4SLinus Torvalds      return only 8 bytes of payload. It is the end.
811da177e4SLinus Torvalds 
821da177e4SLinus Torvalds    Hence, if we want that OSPF worked or traceroute said something reasonable,
831da177e4SLinus Torvalds    we should search for another solution.
841da177e4SLinus Torvalds 
851da177e4SLinus Torvalds    One of them is to parse packet trying to detect inner encapsulation
861da177e4SLinus Torvalds    made by our node. It is difficult or even impossible, especially,
87bff52857Sstephen hemminger    taking into account fragmentation. TO be short, ttl is not solution at all.
881da177e4SLinus Torvalds 
891da177e4SLinus Torvalds    Current solution: The solution was UNEXPECTEDLY SIMPLE.
901da177e4SLinus Torvalds    We force DF flag on tunnels with preconfigured hop limit,
911da177e4SLinus Torvalds    that is ALL. :-) Well, it does not remove the problem completely,
921da177e4SLinus Torvalds    but exponential growth of network traffic is changed to linear
931da177e4SLinus Torvalds    (branches, that exceed pmtu are pruned) and tunnel mtu
94bff52857Sstephen hemminger    rapidly degrades to value <68, where looping stops.
951da177e4SLinus Torvalds    Yes, it is not good if there exists a router in the loop,
961da177e4SLinus Torvalds    which does not force DF, even when encapsulating packets have DF set.
971da177e4SLinus Torvalds    But it is not our problem! Nobody could accuse us, we made
981da177e4SLinus Torvalds    all that we could make. Even if it is your gated who injected
991da177e4SLinus Torvalds    fatal route to network, even if it were you who configured
1001da177e4SLinus Torvalds    fatal static route: you are innocent. :-)
1011da177e4SLinus Torvalds 
1021da177e4SLinus Torvalds    Alexey Kuznetsov.
1031da177e4SLinus Torvalds  */
1041da177e4SLinus Torvalds 
105eccc1bb8Sstephen hemminger static bool log_ecn_error = true;
106eccc1bb8Sstephen hemminger module_param(log_ecn_error, bool, 0644);
107eccc1bb8Sstephen hemminger MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN");
108eccc1bb8Sstephen hemminger 
109c19e654dSHerbert Xu static struct rtnl_link_ops ipgre_link_ops __read_mostly;
1101da177e4SLinus Torvalds static int ipgre_tunnel_init(struct net_device *dev);
1111a66a836SWilliam Tu static void erspan_build_header(struct sk_buff *skb,
112c69de58bSWilliam Tu 				u32 id, u32 index,
113a3222dc9SWilliam Tu 				bool truncate, bool is_ipv4);
114eb8ce741SPavel Emelyanov 
115c7d03a00SAlexey Dobriyan static unsigned int ipgre_net_id __read_mostly;
116c7d03a00SAlexey Dobriyan static unsigned int gre_tap_net_id __read_mostly;
11784e54fe0SWilliam Tu static unsigned int erspan_net_id __read_mostly;
118eb8ce741SPavel Emelyanov 
11932bbd879SStefano Brivio static int ipgre_err(struct sk_buff *skb, u32 info,
120bda7bb46SPravin B Shelar 		     const struct tnl_ptk_info *tpi)
1211da177e4SLinus Torvalds {
1221da177e4SLinus Torvalds 
123071f92d0SRami Rosen 	/* All the routers (except for Linux) return only
1241da177e4SLinus Torvalds 	   8 bytes of packet payload. It means, that precise relaying of
1251da177e4SLinus Torvalds 	   ICMP in the real Internet is absolutely infeasible.
1261da177e4SLinus Torvalds 
1271da177e4SLinus Torvalds 	   Moreover, Cisco "wise men" put GRE key to the third word
128c5441932SPravin B Shelar 	   in GRE header. It makes impossible maintaining even soft
129c5441932SPravin B Shelar 	   state for keyed GRE tunnels with enabled checksum. Tell
130c5441932SPravin B Shelar 	   them "thank you".
1311da177e4SLinus Torvalds 
1321da177e4SLinus Torvalds 	   Well, I wonder, rfc1812 was written by Cisco employee,
133bff52857Sstephen hemminger 	   what the hell these idiots break standards established
134bff52857Sstephen hemminger 	   by themselves???
1351da177e4SLinus Torvalds 	   */
136c5441932SPravin B Shelar 	struct net *net = dev_net(skb->dev);
137c5441932SPravin B Shelar 	struct ip_tunnel_net *itn;
13896f5a846SEric Dumazet 	const struct iphdr *iph;
13988c7664fSArnaldo Carvalho de Melo 	const int type = icmp_hdr(skb)->type;
14088c7664fSArnaldo Carvalho de Melo 	const int code = icmp_hdr(skb)->code;
14120e1954fSEric Dumazet 	unsigned int data_len = 0;
1421da177e4SLinus Torvalds 	struct ip_tunnel *t;
143d2083287Sstephen hemminger 
144bda7bb46SPravin B Shelar 	if (tpi->proto == htons(ETH_P_TEB))
145c5441932SPravin B Shelar 		itn = net_generic(net, gre_tap_net_id);
14651dc63e3SHaishuang Yan 	else if (tpi->proto == htons(ETH_P_ERSPAN) ||
14751dc63e3SHaishuang Yan 		 tpi->proto == htons(ETH_P_ERSPAN2))
14851dc63e3SHaishuang Yan 		itn = net_generic(net, erspan_net_id);
149c5441932SPravin B Shelar 	else
150c5441932SPravin B Shelar 		itn = net_generic(net, ipgre_net_id);
151c5441932SPravin B Shelar 
152c0c0c50fSDuan Jiong 	iph = (const struct iphdr *)(icmp_hdr(skb) + 1);
153bda7bb46SPravin B Shelar 	t = ip_tunnel_lookup(itn, skb->dev->ifindex, tpi->flags,
154bda7bb46SPravin B Shelar 			     iph->daddr, iph->saddr, tpi->key);
155d2083287Sstephen hemminger 
15651456b29SIan Morris 	if (!t)
15732bbd879SStefano Brivio 		return -ENOENT;
15832bbd879SStefano Brivio 
15932bbd879SStefano Brivio 	switch (type) {
16032bbd879SStefano Brivio 	default:
16132bbd879SStefano Brivio 	case ICMP_PARAMETERPROB:
16232bbd879SStefano Brivio 		return 0;
16332bbd879SStefano Brivio 
16432bbd879SStefano Brivio 	case ICMP_DEST_UNREACH:
16532bbd879SStefano Brivio 		switch (code) {
16632bbd879SStefano Brivio 		case ICMP_SR_FAILED:
16732bbd879SStefano Brivio 		case ICMP_PORT_UNREACH:
16832bbd879SStefano Brivio 			/* Impossible event. */
16932bbd879SStefano Brivio 			return 0;
17032bbd879SStefano Brivio 		default:
17132bbd879SStefano Brivio 			/* All others are translated to HOST_UNREACH.
17232bbd879SStefano Brivio 			   rfc2003 contains "deep thoughts" about NET_UNREACH,
17332bbd879SStefano Brivio 			   I believe they are just ether pollution. --ANK
17432bbd879SStefano Brivio 			 */
17532bbd879SStefano Brivio 			break;
17632bbd879SStefano Brivio 		}
17732bbd879SStefano Brivio 		break;
17832bbd879SStefano Brivio 
17932bbd879SStefano Brivio 	case ICMP_TIME_EXCEEDED:
18032bbd879SStefano Brivio 		if (code != ICMP_EXC_TTL)
18132bbd879SStefano Brivio 			return 0;
18232bbd879SStefano Brivio 		data_len = icmp_hdr(skb)->un.reserved[1] * 4; /* RFC 4884 4.1 */
18332bbd879SStefano Brivio 		break;
18432bbd879SStefano Brivio 
18532bbd879SStefano Brivio 	case ICMP_REDIRECT:
18632bbd879SStefano Brivio 		break;
18732bbd879SStefano Brivio 	}
18836393395SDavid S. Miller 
1899b8c6d7bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6)
1909b8c6d7bSEric Dumazet        if (tpi->proto == htons(ETH_P_IPV6) &&
19120e1954fSEric Dumazet            !ip6_err_gen_icmpv6_unreach(skb, iph->ihl * 4 + tpi->hdr_len,
19220e1954fSEric Dumazet 				       type, data_len))
19332bbd879SStefano Brivio                return 0;
1949b8c6d7bSEric Dumazet #endif
1959b8c6d7bSEric Dumazet 
19636393395SDavid S. Miller 	if (t->parms.iph.daddr == 0 ||
197f97c1e0cSJoe Perches 	    ipv4_is_multicast(t->parms.iph.daddr))
19832bbd879SStefano Brivio 		return 0;
1991da177e4SLinus Torvalds 
2001da177e4SLinus Torvalds 	if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED)
20132bbd879SStefano Brivio 		return 0;
2021da177e4SLinus Torvalds 
203da6185d8SWei Yongjun 	if (time_before(jiffies, t->err_time + IPTUNNEL_ERR_TIMEO))
2041da177e4SLinus Torvalds 		t->err_count++;
2051da177e4SLinus Torvalds 	else
2061da177e4SLinus Torvalds 		t->err_count = 1;
2071da177e4SLinus Torvalds 	t->err_time = jiffies;
20832bbd879SStefano Brivio 
20932bbd879SStefano Brivio 	return 0;
2109f57c67cSPravin B Shelar }
2119f57c67cSPravin B Shelar 
2129f57c67cSPravin B Shelar static void gre_err(struct sk_buff *skb, u32 info)
2139f57c67cSPravin B Shelar {
2149f57c67cSPravin B Shelar 	/* All the routers (except for Linux) return only
2159f57c67cSPravin B Shelar 	 * 8 bytes of packet payload. It means, that precise relaying of
2169f57c67cSPravin B Shelar 	 * ICMP in the real Internet is absolutely infeasible.
2179f57c67cSPravin B Shelar 	 *
2189f57c67cSPravin B Shelar 	 * Moreover, Cisco "wise men" put GRE key to the third word
2199f57c67cSPravin B Shelar 	 * in GRE header. It makes impossible maintaining even soft
2209f57c67cSPravin B Shelar 	 * state for keyed
2219f57c67cSPravin B Shelar 	 * GRE tunnels with enabled checksum. Tell them "thank you".
2229f57c67cSPravin B Shelar 	 *
2239f57c67cSPravin B Shelar 	 * Well, I wonder, rfc1812 was written by Cisco employee,
2249f57c67cSPravin B Shelar 	 * what the hell these idiots break standards established
2259f57c67cSPravin B Shelar 	 * by themselves???
2269f57c67cSPravin B Shelar 	 */
2279f57c67cSPravin B Shelar 
228e582615aSEric Dumazet 	const struct iphdr *iph = (struct iphdr *)skb->data;
2299f57c67cSPravin B Shelar 	const int type = icmp_hdr(skb)->type;
2309f57c67cSPravin B Shelar 	const int code = icmp_hdr(skb)->code;
2319f57c67cSPravin B Shelar 	struct tnl_ptk_info tpi;
2329f57c67cSPravin B Shelar 
233b0350d51SHaishuang Yan 	if (gre_parse_header(skb, &tpi, NULL, htons(ETH_P_IP),
234b0350d51SHaishuang Yan 			     iph->ihl * 4) < 0)
2359f57c67cSPravin B Shelar 		return;
2369f57c67cSPravin B Shelar 
2379f57c67cSPravin B Shelar 	if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) {
2389f57c67cSPravin B Shelar 		ipv4_update_pmtu(skb, dev_net(skb->dev), info,
239d888f396SMaciej Żenczykowski 				 skb->dev->ifindex, IPPROTO_GRE);
2409f57c67cSPravin B Shelar 		return;
2419f57c67cSPravin B Shelar 	}
2429f57c67cSPravin B Shelar 	if (type == ICMP_REDIRECT) {
2431042caa7SMaciej Żenczykowski 		ipv4_redirect(skb, dev_net(skb->dev), skb->dev->ifindex,
2441042caa7SMaciej Żenczykowski 			      IPPROTO_GRE);
2459f57c67cSPravin B Shelar 		return;
2469f57c67cSPravin B Shelar 	}
2479f57c67cSPravin B Shelar 
2489f57c67cSPravin B Shelar 	ipgre_err(skb, info, &tpi);
2491da177e4SLinus Torvalds }
2501da177e4SLinus Torvalds 
251f989d546SWilliam Tu static bool is_erspan_type1(int gre_hdr_len)
252f989d546SWilliam Tu {
253f989d546SWilliam Tu 	/* Both ERSPAN type I (version 0) and type II (version 1) use
254f989d546SWilliam Tu 	 * protocol 0x88BE, but the type I has only 4-byte GRE header,
255f989d546SWilliam Tu 	 * while type II has 8-byte.
256f989d546SWilliam Tu 	 */
257f989d546SWilliam Tu 	return gre_hdr_len == 4;
258f989d546SWilliam Tu }
259f989d546SWilliam Tu 
26084e54fe0SWilliam Tu static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi,
26184e54fe0SWilliam Tu 		      int gre_hdr_len)
26284e54fe0SWilliam Tu {
26384e54fe0SWilliam Tu 	struct net *net = dev_net(skb->dev);
26484e54fe0SWilliam Tu 	struct metadata_dst *tun_dst = NULL;
2651d7e2ed2SWilliam Tu 	struct erspan_base_hdr *ershdr;
26684e54fe0SWilliam Tu 	struct ip_tunnel_net *itn;
26784e54fe0SWilliam Tu 	struct ip_tunnel *tunnel;
26884e54fe0SWilliam Tu 	const struct iphdr *iph;
2693df19283SWilliam Tu 	struct erspan_md2 *md2;
2701d7e2ed2SWilliam Tu 	int ver;
27184e54fe0SWilliam Tu 	int len;
27284e54fe0SWilliam Tu 
27384e54fe0SWilliam Tu 	itn = net_generic(net, erspan_net_id);
27484e54fe0SWilliam Tu 	iph = ip_hdr(skb);
275f989d546SWilliam Tu 	if (is_erspan_type1(gre_hdr_len)) {
276f989d546SWilliam Tu 		ver = 0;
277f989d546SWilliam Tu 		tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex,
278f989d546SWilliam Tu 					  tpi->flags | TUNNEL_NO_KEY,
279f989d546SWilliam Tu 					  iph->saddr, iph->daddr, 0);
280f989d546SWilliam Tu 	} else {
2811d7e2ed2SWilliam Tu 		ershdr = (struct erspan_base_hdr *)(skb->data + gre_hdr_len);
282c69de58bSWilliam Tu 		ver = ershdr->ver;
28384e54fe0SWilliam Tu 		tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex,
28484e54fe0SWilliam Tu 					  tpi->flags | TUNNEL_KEY,
28584e54fe0SWilliam Tu 					  iph->saddr, iph->daddr, tpi->key);
286f989d546SWilliam Tu 	}
28784e54fe0SWilliam Tu 
28884e54fe0SWilliam Tu 	if (tunnel) {
289f989d546SWilliam Tu 		if (is_erspan_type1(gre_hdr_len))
290f989d546SWilliam Tu 			len = gre_hdr_len;
291f989d546SWilliam Tu 		else
2921d7e2ed2SWilliam Tu 			len = gre_hdr_len + erspan_hdr_len(ver);
293f989d546SWilliam Tu 
2941d7e2ed2SWilliam Tu 		if (unlikely(!pskb_may_pull(skb, len)))
295ae3e1337SWilliam Tu 			return PACKET_REJECT;
2961d7e2ed2SWilliam Tu 
29784e54fe0SWilliam Tu 		if (__iptunnel_pull_header(skb,
2981d7e2ed2SWilliam Tu 					   len,
29984e54fe0SWilliam Tu 					   htons(ETH_P_TEB),
30084e54fe0SWilliam Tu 					   false, false) < 0)
30184e54fe0SWilliam Tu 			goto drop;
30284e54fe0SWilliam Tu 
3031a66a836SWilliam Tu 		if (tunnel->collect_md) {
304492b67e2SLorenzo Bianconi 			struct erspan_metadata *pkt_md, *md;
3051a66a836SWilliam Tu 			struct ip_tunnel_info *info;
306492b67e2SLorenzo Bianconi 			unsigned char *gh;
3071a66a836SWilliam Tu 			__be64 tun_id;
3081a66a836SWilliam Tu 			__be16 flags;
3091a66a836SWilliam Tu 
3101a66a836SWilliam Tu 			tpi->flags |= TUNNEL_KEY;
3111a66a836SWilliam Tu 			flags = tpi->flags;
3121a66a836SWilliam Tu 			tun_id = key32_to_tunnel_id(tpi->key);
3131a66a836SWilliam Tu 
3141a66a836SWilliam Tu 			tun_dst = ip_tun_rx_dst(skb, flags,
3151a66a836SWilliam Tu 						tun_id, sizeof(*md));
3161a66a836SWilliam Tu 			if (!tun_dst)
3171a66a836SWilliam Tu 				return PACKET_REJECT;
3181a66a836SWilliam Tu 
319492b67e2SLorenzo Bianconi 			/* skb can be uncloned in __iptunnel_pull_header, so
320492b67e2SLorenzo Bianconi 			 * old pkt_md is no longer valid and we need to reset
321492b67e2SLorenzo Bianconi 			 * it
322492b67e2SLorenzo Bianconi 			 */
323492b67e2SLorenzo Bianconi 			gh = skb_network_header(skb) +
324492b67e2SLorenzo Bianconi 			     skb_network_header_len(skb);
325492b67e2SLorenzo Bianconi 			pkt_md = (struct erspan_metadata *)(gh + gre_hdr_len +
326492b67e2SLorenzo Bianconi 							    sizeof(*ershdr));
3271a66a836SWilliam Tu 			md = ip_tunnel_info_opts(&tun_dst->u.tun_info);
328f551c91dSWilliam Tu 			md->version = ver;
3293df19283SWilliam Tu 			md2 = &md->u.md2;
3303df19283SWilliam Tu 			memcpy(md2, pkt_md, ver == 1 ? ERSPAN_V1_MDSIZE :
3313df19283SWilliam Tu 						       ERSPAN_V2_MDSIZE);
332f551c91dSWilliam Tu 
3331a66a836SWilliam Tu 			info = &tun_dst->u.tun_info;
3341a66a836SWilliam Tu 			info->key.tun_flags |= TUNNEL_ERSPAN_OPT;
3351a66a836SWilliam Tu 			info->options_len = sizeof(*md);
3361a66a836SWilliam Tu 		}
3371a66a836SWilliam Tu 
33884e54fe0SWilliam Tu 		skb_reset_mac_header(skb);
33984e54fe0SWilliam Tu 		ip_tunnel_rcv(tunnel, skb, tpi, tun_dst, log_ecn_error);
34084e54fe0SWilliam Tu 		return PACKET_RCVD;
34184e54fe0SWilliam Tu 	}
3425a64506bSHaishuang Yan 	return PACKET_REJECT;
3435a64506bSHaishuang Yan 
34484e54fe0SWilliam Tu drop:
34584e54fe0SWilliam Tu 	kfree_skb(skb);
34684e54fe0SWilliam Tu 	return PACKET_RCVD;
34784e54fe0SWilliam Tu }
34884e54fe0SWilliam Tu 
349125372faSJiri Benc static int __ipgre_rcv(struct sk_buff *skb, const struct tnl_ptk_info *tpi,
350125372faSJiri Benc 		       struct ip_tunnel_net *itn, int hdr_len, bool raw_proto)
3511da177e4SLinus Torvalds {
3522e15ea39SPravin B Shelar 	struct metadata_dst *tun_dst = NULL;
353b71d1d42SEric Dumazet 	const struct iphdr *iph;
3541da177e4SLinus Torvalds 	struct ip_tunnel *tunnel;
3551da177e4SLinus Torvalds 
356eddc9ec5SArnaldo Carvalho de Melo 	iph = ip_hdr(skb);
357bda7bb46SPravin B Shelar 	tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, tpi->flags,
358bda7bb46SPravin B Shelar 				  iph->saddr, iph->daddr, tpi->key);
3591da177e4SLinus Torvalds 
360d2083287Sstephen hemminger 	if (tunnel) {
361c0d59da7Swenxu 		const struct iphdr *tnl_params;
362c0d59da7Swenxu 
363125372faSJiri Benc 		if (__iptunnel_pull_header(skb, hdr_len, tpi->proto,
364125372faSJiri Benc 					   raw_proto, false) < 0)
365244a797bSJiri Benc 			goto drop;
366244a797bSJiri Benc 
367e271c7b4SJiri Benc 		if (tunnel->dev->type != ARPHRD_NONE)
3680e3da5bbSTimo Teräs 			skb_pop_mac_header(skb);
369e271c7b4SJiri Benc 		else
370e271c7b4SJiri Benc 			skb_reset_mac_header(skb);
371c0d59da7Swenxu 
372c0d59da7Swenxu 		tnl_params = &tunnel->parms.iph;
373c0d59da7Swenxu 		if (tunnel->collect_md || tnl_params->daddr == 0) {
374c29a70d2SPravin B Shelar 			__be16 flags;
375c29a70d2SPravin B Shelar 			__be64 tun_id;
3762e15ea39SPravin B Shelar 
377c29a70d2SPravin B Shelar 			flags = tpi->flags & (TUNNEL_CSUM | TUNNEL_KEY);
378d817f432SAmir Vadai 			tun_id = key32_to_tunnel_id(tpi->key);
379c29a70d2SPravin B Shelar 			tun_dst = ip_tun_rx_dst(skb, flags, tun_id, 0);
3802e15ea39SPravin B Shelar 			if (!tun_dst)
3812e15ea39SPravin B Shelar 				return PACKET_REJECT;
3822e15ea39SPravin B Shelar 		}
3832e15ea39SPravin B Shelar 
3842e15ea39SPravin B Shelar 		ip_tunnel_rcv(tunnel, skb, tpi, tun_dst, log_ecn_error);
385bda7bb46SPravin B Shelar 		return PACKET_RCVD;
3861da177e4SLinus Torvalds 	}
387125372faSJiri Benc 	return PACKET_NEXT;
388244a797bSJiri Benc 
389244a797bSJiri Benc drop:
390244a797bSJiri Benc 	kfree_skb(skb);
391244a797bSJiri Benc 	return PACKET_RCVD;
3921da177e4SLinus Torvalds }
3931da177e4SLinus Torvalds 
394125372faSJiri Benc static int ipgre_rcv(struct sk_buff *skb, const struct tnl_ptk_info *tpi,
395125372faSJiri Benc 		     int hdr_len)
396125372faSJiri Benc {
397125372faSJiri Benc 	struct net *net = dev_net(skb->dev);
398125372faSJiri Benc 	struct ip_tunnel_net *itn;
399125372faSJiri Benc 	int res;
400125372faSJiri Benc 
401125372faSJiri Benc 	if (tpi->proto == htons(ETH_P_TEB))
402125372faSJiri Benc 		itn = net_generic(net, gre_tap_net_id);
403125372faSJiri Benc 	else
404125372faSJiri Benc 		itn = net_generic(net, ipgre_net_id);
405125372faSJiri Benc 
406125372faSJiri Benc 	res = __ipgre_rcv(skb, tpi, itn, hdr_len, false);
407125372faSJiri Benc 	if (res == PACKET_NEXT && tpi->proto == htons(ETH_P_TEB)) {
408125372faSJiri Benc 		/* ipgre tunnels in collect metadata mode should receive
409125372faSJiri Benc 		 * also ETH_P_TEB traffic.
410125372faSJiri Benc 		 */
411125372faSJiri Benc 		itn = net_generic(net, ipgre_net_id);
412125372faSJiri Benc 		res = __ipgre_rcv(skb, tpi, itn, hdr_len, true);
413125372faSJiri Benc 	}
414125372faSJiri Benc 	return res;
415125372faSJiri Benc }
416125372faSJiri Benc 
4179f57c67cSPravin B Shelar static int gre_rcv(struct sk_buff *skb)
4189f57c67cSPravin B Shelar {
4199f57c67cSPravin B Shelar 	struct tnl_ptk_info tpi;
4209f57c67cSPravin B Shelar 	bool csum_err = false;
42195f5c64cSTom Herbert 	int hdr_len;
4229f57c67cSPravin B Shelar 
4239f57c67cSPravin B Shelar #ifdef CONFIG_NET_IPGRE_BROADCAST
4249f57c67cSPravin B Shelar 	if (ipv4_is_multicast(ip_hdr(skb)->daddr)) {
4259f57c67cSPravin B Shelar 		/* Looped back packet, drop it! */
4269f57c67cSPravin B Shelar 		if (rt_is_output_route(skb_rtable(skb)))
4279f57c67cSPravin B Shelar 			goto drop;
4289f57c67cSPravin B Shelar 	}
4299f57c67cSPravin B Shelar #endif
4309f57c67cSPravin B Shelar 
431e582615aSEric Dumazet 	hdr_len = gre_parse_header(skb, &tpi, &csum_err, htons(ETH_P_IP), 0);
432f132ae7cSJiri Benc 	if (hdr_len < 0)
43395f5c64cSTom Herbert 		goto drop;
43495f5c64cSTom Herbert 
435f551c91dSWilliam Tu 	if (unlikely(tpi.proto == htons(ETH_P_ERSPAN) ||
436f551c91dSWilliam Tu 		     tpi.proto == htons(ETH_P_ERSPAN2))) {
43784e54fe0SWilliam Tu 		if (erspan_rcv(skb, &tpi, hdr_len) == PACKET_RCVD)
43884e54fe0SWilliam Tu 			return 0;
439dd8d5b8cSHaishuang Yan 		goto out;
44084e54fe0SWilliam Tu 	}
44184e54fe0SWilliam Tu 
442244a797bSJiri Benc 	if (ipgre_rcv(skb, &tpi, hdr_len) == PACKET_RCVD)
4439f57c67cSPravin B Shelar 		return 0;
4449f57c67cSPravin B Shelar 
445dd8d5b8cSHaishuang Yan out:
4469f57c67cSPravin B Shelar 	icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
4479f57c67cSPravin B Shelar drop:
4489f57c67cSPravin B Shelar 	kfree_skb(skb);
4499f57c67cSPravin B Shelar 	return 0;
4509f57c67cSPravin B Shelar }
4519f57c67cSPravin B Shelar 
452c5441932SPravin B Shelar static void __gre_xmit(struct sk_buff *skb, struct net_device *dev,
453c5441932SPravin B Shelar 		       const struct iphdr *tnl_params,
454c5441932SPravin B Shelar 		       __be16 proto)
455c5441932SPravin B Shelar {
456c5441932SPravin B Shelar 	struct ip_tunnel *tunnel = netdev_priv(dev);
457c5441932SPravin B Shelar 
458c5441932SPravin B Shelar 	if (tunnel->parms.o_flags & TUNNEL_SEQ)
459c5441932SPravin B Shelar 		tunnel->o_seqno++;
460cef401deSEric Dumazet 
461c5441932SPravin B Shelar 	/* Push GRE header. */
462182a352dSTom Herbert 	gre_build_header(skb, tunnel->tun_hlen,
463182a352dSTom Herbert 			 tunnel->parms.o_flags, proto, tunnel->parms.o_key,
464182a352dSTom Herbert 			 htonl(tunnel->o_seqno));
4651da177e4SLinus Torvalds 
466bf3d6a8fSNicolas Dichtel 	ip_tunnel_xmit(skb, dev, tnl_params, tnl_params->protocol);
4671da177e4SLinus Torvalds }
4681da177e4SLinus Torvalds 
469aed069dfSAlexander Duyck static int gre_handle_offloads(struct sk_buff *skb, bool csum)
470b2acd1dcSPravin B Shelar {
4716fa79666SEdward Cree 	return iptunnel_handle_offloads(skb, csum ? SKB_GSO_GRE_CSUM : SKB_GSO_GRE);
472b2acd1dcSPravin B Shelar }
473b2acd1dcSPravin B Shelar 
474862a03c3SWilliam Tu static void gre_fb_xmit(struct sk_buff *skb, struct net_device *dev,
475862a03c3SWilliam Tu 			__be16 proto)
476862a03c3SWilliam Tu {
47777a5196aSWilliam Tu 	struct ip_tunnel *tunnel = netdev_priv(dev);
478862a03c3SWilliam Tu 	struct ip_tunnel_info *tun_info;
479862a03c3SWilliam Tu 	const struct ip_tunnel_key *key;
480862a03c3SWilliam Tu 	int tunnel_hlen;
481962924faSwenxu 	__be16 flags;
482862a03c3SWilliam Tu 
483862a03c3SWilliam Tu 	tun_info = skb_tunnel_info(skb);
484862a03c3SWilliam Tu 	if (unlikely(!tun_info || !(tun_info->mode & IP_TUNNEL_INFO_TX) ||
485862a03c3SWilliam Tu 		     ip_tunnel_info_af(tun_info) != AF_INET))
486862a03c3SWilliam Tu 		goto err_free_skb;
487862a03c3SWilliam Tu 
488862a03c3SWilliam Tu 	key = &tun_info->key;
489862a03c3SWilliam Tu 	tunnel_hlen = gre_calc_hlen(key->tun_flags);
490862a03c3SWilliam Tu 
491962924faSwenxu 	if (skb_cow_head(skb, dev->needed_headroom))
492962924faSwenxu 		goto err_free_skb;
4932e15ea39SPravin B Shelar 
4942e15ea39SPravin B Shelar 	/* Push Tunnel header. */
495aed069dfSAlexander Duyck 	if (gre_handle_offloads(skb, !!(tun_info->key.tun_flags & TUNNEL_CSUM)))
496962924faSwenxu 		goto err_free_skb;
4972e15ea39SPravin B Shelar 
49877a5196aSWilliam Tu 	flags = tun_info->key.tun_flags &
49977a5196aSWilliam Tu 		(TUNNEL_CSUM | TUNNEL_KEY | TUNNEL_SEQ);
500cba65321SDavid S. Miller 	gre_build_header(skb, tunnel_hlen, flags, proto,
50177a5196aSWilliam Tu 			 tunnel_id_to_key32(tun_info->key.tun_id),
50215746394SColin Ian King 			 (flags & TUNNEL_SEQ) ? htonl(tunnel->o_seqno++) : 0);
5032e15ea39SPravin B Shelar 
504962924faSwenxu 	ip_md_tunnel_xmit(skb, dev, IPPROTO_GRE, tunnel_hlen);
505039f5062SPravin B Shelar 
5062e15ea39SPravin B Shelar 	return;
5072e15ea39SPravin B Shelar 
5082e15ea39SPravin B Shelar err_free_skb:
5092e15ea39SPravin B Shelar 	kfree_skb(skb);
5102e15ea39SPravin B Shelar 	dev->stats.tx_dropped++;
5112e15ea39SPravin B Shelar }
5122e15ea39SPravin B Shelar 
51320704bd1SXin Long static void erspan_fb_xmit(struct sk_buff *skb, struct net_device *dev)
5141a66a836SWilliam Tu {
5151a66a836SWilliam Tu 	struct ip_tunnel *tunnel = netdev_priv(dev);
5161a66a836SWilliam Tu 	struct ip_tunnel_info *tun_info;
5171a66a836SWilliam Tu 	const struct ip_tunnel_key *key;
5181a66a836SWilliam Tu 	struct erspan_metadata *md;
5191a66a836SWilliam Tu 	bool truncate = false;
520962924faSwenxu 	__be16 proto;
5211a66a836SWilliam Tu 	int tunnel_hlen;
522f551c91dSWilliam Tu 	int version;
5231baf5ebfSWilliam Tu 	int nhoff;
524d5db21a3SWilliam Tu 	int thoff;
5251a66a836SWilliam Tu 
5261a66a836SWilliam Tu 	tun_info = skb_tunnel_info(skb);
5271a66a836SWilliam Tu 	if (unlikely(!tun_info || !(tun_info->mode & IP_TUNNEL_INFO_TX) ||
5281a66a836SWilliam Tu 		     ip_tunnel_info_af(tun_info) != AF_INET))
5291a66a836SWilliam Tu 		goto err_free_skb;
5301a66a836SWilliam Tu 
5311a66a836SWilliam Tu 	key = &tun_info->key;
532256c87c1SPieter Jansen van Vuuren 	if (!(tun_info->key.tun_flags & TUNNEL_ERSPAN_OPT))
533962924faSwenxu 		goto err_free_skb;
5342eb8d6d2SXin Long 	if (tun_info->options_len < sizeof(*md))
535962924faSwenxu 		goto err_free_skb;
5362eb8d6d2SXin Long 	md = ip_tunnel_info_opts(tun_info);
5371a66a836SWilliam Tu 
5381a66a836SWilliam Tu 	/* ERSPAN has fixed 8 byte GRE header */
539f551c91dSWilliam Tu 	version = md->version;
540f551c91dSWilliam Tu 	tunnel_hlen = 8 + erspan_hdr_len(version);
5411a66a836SWilliam Tu 
542962924faSwenxu 	if (skb_cow_head(skb, dev->needed_headroom))
543962924faSwenxu 		goto err_free_skb;
5441a66a836SWilliam Tu 
5451a66a836SWilliam Tu 	if (gre_handle_offloads(skb, false))
546962924faSwenxu 		goto err_free_skb;
5471a66a836SWilliam Tu 
548f192970dSWilliam Tu 	if (skb->len > dev->mtu + dev->hard_header_len) {
549f192970dSWilliam Tu 		pskb_trim(skb, dev->mtu + dev->hard_header_len);
5501a66a836SWilliam Tu 		truncate = true;
5511a66a836SWilliam Tu 	}
5521a66a836SWilliam Tu 
5531baf5ebfSWilliam Tu 	nhoff = skb_network_header(skb) - skb_mac_header(skb);
5541baf5ebfSWilliam Tu 	if (skb->protocol == htons(ETH_P_IP) &&
5551baf5ebfSWilliam Tu 	    (ntohs(ip_hdr(skb)->tot_len) > skb->len - nhoff))
5561baf5ebfSWilliam Tu 		truncate = true;
5571baf5ebfSWilliam Tu 
558d5db21a3SWilliam Tu 	thoff = skb_transport_header(skb) - skb_mac_header(skb);
559d5db21a3SWilliam Tu 	if (skb->protocol == htons(ETH_P_IPV6) &&
560d5db21a3SWilliam Tu 	    (ntohs(ipv6_hdr(skb)->payload_len) > skb->len - thoff))
561d5db21a3SWilliam Tu 		truncate = true;
562d5db21a3SWilliam Tu 
563f551c91dSWilliam Tu 	if (version == 1) {
564c69de58bSWilliam Tu 		erspan_build_header(skb, ntohl(tunnel_id_to_key32(key->tun_id)),
5651d7e2ed2SWilliam Tu 				    ntohl(md->u.index), truncate, true);
56620704bd1SXin Long 		proto = htons(ETH_P_ERSPAN);
567f551c91dSWilliam Tu 	} else if (version == 2) {
568c69de58bSWilliam Tu 		erspan_build_header_v2(skb,
569c69de58bSWilliam Tu 				       ntohl(tunnel_id_to_key32(key->tun_id)),
570c69de58bSWilliam Tu 				       md->u.md2.dir,
571c69de58bSWilliam Tu 				       get_hwid(&md->u.md2),
572c69de58bSWilliam Tu 				       truncate, true);
57320704bd1SXin Long 		proto = htons(ETH_P_ERSPAN2);
574f551c91dSWilliam Tu 	} else {
575962924faSwenxu 		goto err_free_skb;
576f551c91dSWilliam Tu 	}
5771a66a836SWilliam Tu 
5781a66a836SWilliam Tu 	gre_build_header(skb, 8, TUNNEL_SEQ,
57920704bd1SXin Long 			 proto, 0, htonl(tunnel->o_seqno++));
5801a66a836SWilliam Tu 
581962924faSwenxu 	ip_md_tunnel_xmit(skb, dev, IPPROTO_GRE, tunnel_hlen);
5821a66a836SWilliam Tu 
5831a66a836SWilliam Tu 	return;
5841a66a836SWilliam Tu 
5851a66a836SWilliam Tu err_free_skb:
5861a66a836SWilliam Tu 	kfree_skb(skb);
5871a66a836SWilliam Tu 	dev->stats.tx_dropped++;
5881a66a836SWilliam Tu }
5891a66a836SWilliam Tu 
590fc4099f1SPravin B Shelar static int gre_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
591fc4099f1SPravin B Shelar {
592fc4099f1SPravin B Shelar 	struct ip_tunnel_info *info = skb_tunnel_info(skb);
593962924faSwenxu 	const struct ip_tunnel_key *key;
594fc4099f1SPravin B Shelar 	struct rtable *rt;
595fc4099f1SPravin B Shelar 	struct flowi4 fl4;
596fc4099f1SPravin B Shelar 
597fc4099f1SPravin B Shelar 	if (ip_tunnel_info_af(info) != AF_INET)
598fc4099f1SPravin B Shelar 		return -EINVAL;
599fc4099f1SPravin B Shelar 
600962924faSwenxu 	key = &info->key;
601962924faSwenxu 	ip_tunnel_init_flow(&fl4, IPPROTO_GRE, key->u.ipv4.dst, key->u.ipv4.src,
602962924faSwenxu 			    tunnel_id_to_key32(key->tun_id), key->tos, 0,
60324ba1440Swenxu 			    skb->mark, skb_get_hash(skb));
604962924faSwenxu 	rt = ip_route_output_key(dev_net(dev), &fl4);
605fc4099f1SPravin B Shelar 	if (IS_ERR(rt))
606fc4099f1SPravin B Shelar 		return PTR_ERR(rt);
607fc4099f1SPravin B Shelar 
608fc4099f1SPravin B Shelar 	ip_rt_put(rt);
609fc4099f1SPravin B Shelar 	info->key.u.ipv4.src = fl4.saddr;
610fc4099f1SPravin B Shelar 	return 0;
611fc4099f1SPravin B Shelar }
612fc4099f1SPravin B Shelar 
613c5441932SPravin B Shelar static netdev_tx_t ipgre_xmit(struct sk_buff *skb,
614c5441932SPravin B Shelar 			      struct net_device *dev)
615ee34c1ebSMichal Schmidt {
616c5441932SPravin B Shelar 	struct ip_tunnel *tunnel = netdev_priv(dev);
617c5441932SPravin B Shelar 	const struct iphdr *tnl_params;
618ee34c1ebSMichal Schmidt 
619cb9f1b78SWillem de Bruijn 	if (!pskb_inet_may_pull(skb))
620cb9f1b78SWillem de Bruijn 		goto free_skb;
621cb9f1b78SWillem de Bruijn 
6222e15ea39SPravin B Shelar 	if (tunnel->collect_md) {
6232090714eSJiri Benc 		gre_fb_xmit(skb, dev, skb->protocol);
6242e15ea39SPravin B Shelar 		return NETDEV_TX_OK;
6252e15ea39SPravin B Shelar 	}
6262e15ea39SPravin B Shelar 
627c5441932SPravin B Shelar 	if (dev->header_ops) {
628c5441932SPravin B Shelar 		/* Need space for new headers */
629c5441932SPravin B Shelar 		if (skb_cow_head(skb, dev->needed_headroom -
6302bac7cb3SChen Gang 				      (tunnel->hlen + sizeof(struct iphdr))))
631c5441932SPravin B Shelar 			goto free_skb;
632ee34c1ebSMichal Schmidt 
633c5441932SPravin B Shelar 		tnl_params = (const struct iphdr *)skb->data;
634cbb1e85fSDavid S. Miller 
635c5441932SPravin B Shelar 		/* Pull skb since ip_tunnel_xmit() needs skb->data pointing
636c5441932SPravin B Shelar 		 * to gre header.
637c5441932SPravin B Shelar 		 */
638c5441932SPravin B Shelar 		skb_pull(skb, tunnel->hlen + sizeof(struct iphdr));
6398a0033a9STimo Teräs 		skb_reset_mac_header(skb);
640c5441932SPravin B Shelar 	} else {
641c5441932SPravin B Shelar 		if (skb_cow_head(skb, dev->needed_headroom))
642c5441932SPravin B Shelar 			goto free_skb;
643c5441932SPravin B Shelar 
644c5441932SPravin B Shelar 		tnl_params = &tunnel->parms.iph;
645ee34c1ebSMichal Schmidt 	}
646e1a80002SHerbert Xu 
647aed069dfSAlexander Duyck 	if (gre_handle_offloads(skb, !!(tunnel->parms.o_flags & TUNNEL_CSUM)))
648aed069dfSAlexander Duyck 		goto free_skb;
6498a0033a9STimo Teräs 
650c5441932SPravin B Shelar 	__gre_xmit(skb, dev, tnl_params, skb->protocol);
651c5441932SPravin B Shelar 	return NETDEV_TX_OK;
652c5441932SPravin B Shelar 
653c5441932SPravin B Shelar free_skb:
6543acfa1e7SEric Dumazet 	kfree_skb(skb);
655c5441932SPravin B Shelar 	dev->stats.tx_dropped++;
656c5441932SPravin B Shelar 	return NETDEV_TX_OK;
657ee34c1ebSMichal Schmidt }
658ee34c1ebSMichal Schmidt 
65984e54fe0SWilliam Tu static netdev_tx_t erspan_xmit(struct sk_buff *skb,
66084e54fe0SWilliam Tu 			       struct net_device *dev)
66184e54fe0SWilliam Tu {
66284e54fe0SWilliam Tu 	struct ip_tunnel *tunnel = netdev_priv(dev);
66384e54fe0SWilliam Tu 	bool truncate = false;
66420704bd1SXin Long 	__be16 proto;
66584e54fe0SWilliam Tu 
666cb9f1b78SWillem de Bruijn 	if (!pskb_inet_may_pull(skb))
667cb9f1b78SWillem de Bruijn 		goto free_skb;
668cb9f1b78SWillem de Bruijn 
6691a66a836SWilliam Tu 	if (tunnel->collect_md) {
67020704bd1SXin Long 		erspan_fb_xmit(skb, dev);
6711a66a836SWilliam Tu 		return NETDEV_TX_OK;
6721a66a836SWilliam Tu 	}
6731a66a836SWilliam Tu 
67484e54fe0SWilliam Tu 	if (gre_handle_offloads(skb, false))
67584e54fe0SWilliam Tu 		goto free_skb;
67684e54fe0SWilliam Tu 
67784e54fe0SWilliam Tu 	if (skb_cow_head(skb, dev->needed_headroom))
67884e54fe0SWilliam Tu 		goto free_skb;
67984e54fe0SWilliam Tu 
680f192970dSWilliam Tu 	if (skb->len > dev->mtu + dev->hard_header_len) {
681f192970dSWilliam Tu 		pskb_trim(skb, dev->mtu + dev->hard_header_len);
68284e54fe0SWilliam Tu 		truncate = true;
68384e54fe0SWilliam Tu 	}
68484e54fe0SWilliam Tu 
68584e54fe0SWilliam Tu 	/* Push ERSPAN header */
686f989d546SWilliam Tu 	if (tunnel->erspan_ver == 0) {
687f989d546SWilliam Tu 		proto = htons(ETH_P_ERSPAN);
688f989d546SWilliam Tu 		tunnel->parms.o_flags &= ~TUNNEL_SEQ;
689f989d546SWilliam Tu 	} else if (tunnel->erspan_ver == 1) {
690c69de58bSWilliam Tu 		erspan_build_header(skb, ntohl(tunnel->parms.o_key),
691c69de58bSWilliam Tu 				    tunnel->index,
692a3222dc9SWilliam Tu 				    truncate, true);
69320704bd1SXin Long 		proto = htons(ETH_P_ERSPAN);
69420704bd1SXin Long 	} else if (tunnel->erspan_ver == 2) {
695c69de58bSWilliam Tu 		erspan_build_header_v2(skb, ntohl(tunnel->parms.o_key),
696f551c91dSWilliam Tu 				       tunnel->dir, tunnel->hwid,
697f551c91dSWilliam Tu 				       truncate, true);
69820704bd1SXin Long 		proto = htons(ETH_P_ERSPAN2);
69920704bd1SXin Long 	} else {
70002f99df1SWilliam Tu 		goto free_skb;
70120704bd1SXin Long 	}
702f551c91dSWilliam Tu 
70384e54fe0SWilliam Tu 	tunnel->parms.o_flags &= ~TUNNEL_KEY;
70420704bd1SXin Long 	__gre_xmit(skb, dev, &tunnel->parms.iph, proto);
70584e54fe0SWilliam Tu 	return NETDEV_TX_OK;
70684e54fe0SWilliam Tu 
70784e54fe0SWilliam Tu free_skb:
70884e54fe0SWilliam Tu 	kfree_skb(skb);
70984e54fe0SWilliam Tu 	dev->stats.tx_dropped++;
71084e54fe0SWilliam Tu 	return NETDEV_TX_OK;
71184e54fe0SWilliam Tu }
71284e54fe0SWilliam Tu 
713c5441932SPravin B Shelar static netdev_tx_t gre_tap_xmit(struct sk_buff *skb,
714c5441932SPravin B Shelar 				struct net_device *dev)
715c5441932SPravin B Shelar {
716c5441932SPravin B Shelar 	struct ip_tunnel *tunnel = netdev_priv(dev);
717ee34c1ebSMichal Schmidt 
718cb9f1b78SWillem de Bruijn 	if (!pskb_inet_may_pull(skb))
719cb9f1b78SWillem de Bruijn 		goto free_skb;
720cb9f1b78SWillem de Bruijn 
7212e15ea39SPravin B Shelar 	if (tunnel->collect_md) {
7222090714eSJiri Benc 		gre_fb_xmit(skb, dev, htons(ETH_P_TEB));
7232e15ea39SPravin B Shelar 		return NETDEV_TX_OK;
7242e15ea39SPravin B Shelar 	}
7252e15ea39SPravin B Shelar 
726aed069dfSAlexander Duyck 	if (gre_handle_offloads(skb, !!(tunnel->parms.o_flags & TUNNEL_CSUM)))
727aed069dfSAlexander Duyck 		goto free_skb;
728ee34c1ebSMichal Schmidt 
729c5441932SPravin B Shelar 	if (skb_cow_head(skb, dev->needed_headroom))
730c5441932SPravin B Shelar 		goto free_skb;
73142aa9162SHerbert Xu 
732c5441932SPravin B Shelar 	__gre_xmit(skb, dev, &tunnel->parms.iph, htons(ETH_P_TEB));
733c5441932SPravin B Shelar 	return NETDEV_TX_OK;
734c5441932SPravin B Shelar 
735c5441932SPravin B Shelar free_skb:
7363acfa1e7SEric Dumazet 	kfree_skb(skb);
737c5441932SPravin B Shelar 	dev->stats.tx_dropped++;
738c5441932SPravin B Shelar 	return NETDEV_TX_OK;
73968c33163SPravin B Shelar }
740ee34c1ebSMichal Schmidt 
741dd9d598cSXin Long static void ipgre_link_update(struct net_device *dev, bool set_mtu)
742dd9d598cSXin Long {
743dd9d598cSXin Long 	struct ip_tunnel *tunnel = netdev_priv(dev);
744dd9d598cSXin Long 	int len;
745dd9d598cSXin Long 
746dd9d598cSXin Long 	len = tunnel->tun_hlen;
747dd9d598cSXin Long 	tunnel->tun_hlen = gre_calc_hlen(tunnel->parms.o_flags);
748dd9d598cSXin Long 	len = tunnel->tun_hlen - len;
749dd9d598cSXin Long 	tunnel->hlen = tunnel->hlen + len;
750dd9d598cSXin Long 
751dd9d598cSXin Long 	dev->needed_headroom = dev->needed_headroom + len;
752dd9d598cSXin Long 	if (set_mtu)
753dd9d598cSXin Long 		dev->mtu = max_t(int, dev->mtu - len, 68);
754dd9d598cSXin Long 
755dd9d598cSXin Long 	if (!(tunnel->parms.o_flags & TUNNEL_SEQ)) {
756dd9d598cSXin Long 		if (!(tunnel->parms.o_flags & TUNNEL_CSUM) ||
757dd9d598cSXin Long 		    tunnel->encap.type == TUNNEL_ENCAP_NONE) {
758dd9d598cSXin Long 			dev->features |= NETIF_F_GSO_SOFTWARE;
759dd9d598cSXin Long 			dev->hw_features |= NETIF_F_GSO_SOFTWARE;
7601cc5954fSSabrina Dubroca 		} else {
7611cc5954fSSabrina Dubroca 			dev->features &= ~NETIF_F_GSO_SOFTWARE;
7621cc5954fSSabrina Dubroca 			dev->hw_features &= ~NETIF_F_GSO_SOFTWARE;
763dd9d598cSXin Long 		}
764dd9d598cSXin Long 		dev->features |= NETIF_F_LLTX;
7651cc5954fSSabrina Dubroca 	} else {
7661cc5954fSSabrina Dubroca 		dev->hw_features &= ~NETIF_F_GSO_SOFTWARE;
7671cc5954fSSabrina Dubroca 		dev->features &= ~(NETIF_F_LLTX | NETIF_F_GSO_SOFTWARE);
768dd9d598cSXin Long 	}
769dd9d598cSXin Long }
770dd9d598cSXin Long 
771c5441932SPravin B Shelar static int ipgre_tunnel_ioctl(struct net_device *dev,
772c5441932SPravin B Shelar 			      struct ifreq *ifr, int cmd)
7731da177e4SLinus Torvalds {
7741da177e4SLinus Torvalds 	struct ip_tunnel_parm p;
775a0efab67SXin Long 	int err;
7761da177e4SLinus Torvalds 
7771da177e4SLinus Torvalds 	if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
778c5441932SPravin B Shelar 		return -EFAULT;
779a0efab67SXin Long 
7806c734fb8SCong Wang 	if (cmd == SIOCADDTUNNEL || cmd == SIOCCHGTUNNEL) {
7811da177e4SLinus Torvalds 		if (p.iph.version != 4 || p.iph.protocol != IPPROTO_GRE ||
7821da177e4SLinus Torvalds 		    p.iph.ihl != 5 || (p.iph.frag_off & htons(~IP_DF)) ||
7836c734fb8SCong Wang 		    ((p.i_flags | p.o_flags) & (GRE_VERSION | GRE_ROUTING)))
7841da177e4SLinus Torvalds 			return -EINVAL;
785c5441932SPravin B Shelar 	}
786a0efab67SXin Long 
787c5441932SPravin B Shelar 	p.i_flags = gre_flags_to_tnl_flags(p.i_flags);
788c5441932SPravin B Shelar 	p.o_flags = gre_flags_to_tnl_flags(p.o_flags);
789c5441932SPravin B Shelar 
790c5441932SPravin B Shelar 	err = ip_tunnel_ioctl(dev, &p, cmd);
791c5441932SPravin B Shelar 	if (err)
792c5441932SPravin B Shelar 		return err;
793c5441932SPravin B Shelar 
794a0efab67SXin Long 	if (cmd == SIOCCHGTUNNEL) {
795a0efab67SXin Long 		struct ip_tunnel *t = netdev_priv(dev);
796a0efab67SXin Long 
797a0efab67SXin Long 		t->parms.i_flags = p.i_flags;
798a0efab67SXin Long 		t->parms.o_flags = p.o_flags;
799a0efab67SXin Long 
800a0efab67SXin Long 		if (strcmp(dev->rtnl_link_ops->kind, "erspan"))
801a0efab67SXin Long 			ipgre_link_update(dev, true);
802a0efab67SXin Long 	}
803a0efab67SXin Long 
80495f5c64cSTom Herbert 	p.i_flags = gre_tnl_flags_to_gre_flags(p.i_flags);
80595f5c64cSTom Herbert 	p.o_flags = gre_tnl_flags_to_gre_flags(p.o_flags);
806c5441932SPravin B Shelar 
807c5441932SPravin B Shelar 	if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p)))
808c5441932SPravin B Shelar 		return -EFAULT;
809a0efab67SXin Long 
8101da177e4SLinus Torvalds 	return 0;
8111da177e4SLinus Torvalds }
8121da177e4SLinus Torvalds 
8131da177e4SLinus Torvalds /* Nice toy. Unfortunately, useless in real life :-)
8141da177e4SLinus Torvalds    It allows to construct virtual multiprotocol broadcast "LAN"
8151da177e4SLinus Torvalds    over the Internet, provided multicast routing is tuned.
8161da177e4SLinus Torvalds 
8171da177e4SLinus Torvalds 
8181da177e4SLinus Torvalds    I have no idea was this bicycle invented before me,
8191da177e4SLinus Torvalds    so that I had to set ARPHRD_IPGRE to a random value.
8201da177e4SLinus Torvalds    I have an impression, that Cisco could make something similar,
8211da177e4SLinus Torvalds    but this feature is apparently missing in IOS<=11.2(8).
8221da177e4SLinus Torvalds 
8231da177e4SLinus Torvalds    I set up 10.66.66/24 and fec0:6666:6666::0/96 as virtual networks
8241da177e4SLinus Torvalds    with broadcast 224.66.66.66. If you have access to mbone, play with me :-)
8251da177e4SLinus Torvalds 
8261da177e4SLinus Torvalds    ping -t 255 224.66.66.66
8271da177e4SLinus Torvalds 
8281da177e4SLinus Torvalds    If nobody answers, mbone does not work.
8291da177e4SLinus Torvalds 
8301da177e4SLinus Torvalds    ip tunnel add Universe mode gre remote 224.66.66.66 local <Your_real_addr> ttl 255
8311da177e4SLinus Torvalds    ip addr add 10.66.66.<somewhat>/24 dev Universe
8321da177e4SLinus Torvalds    ifconfig Universe up
8331da177e4SLinus Torvalds    ifconfig Universe add fe80::<Your_real_addr>/10
8341da177e4SLinus Torvalds    ifconfig Universe add fec0:6666:6666::<Your_real_addr>/96
8351da177e4SLinus Torvalds    ftp 10.66.66.66
8361da177e4SLinus Torvalds    ...
8371da177e4SLinus Torvalds    ftp fec0:6666:6666::193.233.7.65
8381da177e4SLinus Torvalds    ...
8391da177e4SLinus Torvalds  */
8403b04dddeSStephen Hemminger static int ipgre_header(struct sk_buff *skb, struct net_device *dev,
8413b04dddeSStephen Hemminger 			unsigned short type,
8421507850bSEric Dumazet 			const void *daddr, const void *saddr, unsigned int len)
8431da177e4SLinus Torvalds {
8442941a486SPatrick McHardy 	struct ip_tunnel *t = netdev_priv(dev);
845c5441932SPravin B Shelar 	struct iphdr *iph;
846c5441932SPravin B Shelar 	struct gre_base_hdr *greh;
847c5441932SPravin B Shelar 
848d58ff351SJohannes Berg 	iph = skb_push(skb, t->hlen + sizeof(*iph));
849c5441932SPravin B Shelar 	greh = (struct gre_base_hdr *)(iph+1);
85095f5c64cSTom Herbert 	greh->flags = gre_tnl_flags_to_gre_flags(t->parms.o_flags);
851c5441932SPravin B Shelar 	greh->protocol = htons(type);
8521da177e4SLinus Torvalds 
8531da177e4SLinus Torvalds 	memcpy(iph, &t->parms.iph, sizeof(struct iphdr));
8541da177e4SLinus Torvalds 
855c5441932SPravin B Shelar 	/* Set the source hardware address. */
8561da177e4SLinus Torvalds 	if (saddr)
8571da177e4SLinus Torvalds 		memcpy(&iph->saddr, saddr, 4);
8586d55cb91STimo Teräs 	if (daddr)
8591da177e4SLinus Torvalds 		memcpy(&iph->daddr, daddr, 4);
8606d55cb91STimo Teräs 	if (iph->daddr)
86177a482bdSTimo Teräs 		return t->hlen + sizeof(*iph);
8621da177e4SLinus Torvalds 
863c5441932SPravin B Shelar 	return -(t->hlen + sizeof(*iph));
8641da177e4SLinus Torvalds }
8651da177e4SLinus Torvalds 
8666a5f44d7STimo Teras static int ipgre_header_parse(const struct sk_buff *skb, unsigned char *haddr)
8676a5f44d7STimo Teras {
868b71d1d42SEric Dumazet 	const struct iphdr *iph = (const struct iphdr *) skb_mac_header(skb);
8696a5f44d7STimo Teras 	memcpy(haddr, &iph->saddr, 4);
8706a5f44d7STimo Teras 	return 4;
8716a5f44d7STimo Teras }
8726a5f44d7STimo Teras 
8733b04dddeSStephen Hemminger static const struct header_ops ipgre_header_ops = {
8743b04dddeSStephen Hemminger 	.create	= ipgre_header,
8756a5f44d7STimo Teras 	.parse	= ipgre_header_parse,
8763b04dddeSStephen Hemminger };
8773b04dddeSStephen Hemminger 
8786a5f44d7STimo Teras #ifdef CONFIG_NET_IPGRE_BROADCAST
8791da177e4SLinus Torvalds static int ipgre_open(struct net_device *dev)
8801da177e4SLinus Torvalds {
8812941a486SPatrick McHardy 	struct ip_tunnel *t = netdev_priv(dev);
8821da177e4SLinus Torvalds 
883f97c1e0cSJoe Perches 	if (ipv4_is_multicast(t->parms.iph.daddr)) {
884cbb1e85fSDavid S. Miller 		struct flowi4 fl4;
885cbb1e85fSDavid S. Miller 		struct rtable *rt;
886cbb1e85fSDavid S. Miller 
887b57708adSNicolas Dichtel 		rt = ip_route_output_gre(t->net, &fl4,
88878fbfd8aSDavid S. Miller 					 t->parms.iph.daddr,
88978fbfd8aSDavid S. Miller 					 t->parms.iph.saddr,
89078fbfd8aSDavid S. Miller 					 t->parms.o_key,
89178fbfd8aSDavid S. Miller 					 RT_TOS(t->parms.iph.tos),
89278fbfd8aSDavid S. Miller 					 t->parms.link);
893b23dd4feSDavid S. Miller 		if (IS_ERR(rt))
8941da177e4SLinus Torvalds 			return -EADDRNOTAVAIL;
895d8d1f30bSChangli Gao 		dev = rt->dst.dev;
8961da177e4SLinus Torvalds 		ip_rt_put(rt);
89751456b29SIan Morris 		if (!__in_dev_get_rtnl(dev))
8981da177e4SLinus Torvalds 			return -EADDRNOTAVAIL;
8991da177e4SLinus Torvalds 		t->mlink = dev->ifindex;
900e5ed6399SHerbert Xu 		ip_mc_inc_group(__in_dev_get_rtnl(dev), t->parms.iph.daddr);
9011da177e4SLinus Torvalds 	}
9021da177e4SLinus Torvalds 	return 0;
9031da177e4SLinus Torvalds }
9041da177e4SLinus Torvalds 
9051da177e4SLinus Torvalds static int ipgre_close(struct net_device *dev)
9061da177e4SLinus Torvalds {
9072941a486SPatrick McHardy 	struct ip_tunnel *t = netdev_priv(dev);
908b8c26a33SStephen Hemminger 
909f97c1e0cSJoe Perches 	if (ipv4_is_multicast(t->parms.iph.daddr) && t->mlink) {
9107fee0ca2SDenis V. Lunev 		struct in_device *in_dev;
911b57708adSNicolas Dichtel 		in_dev = inetdev_by_index(t->net, t->mlink);
9128723e1b4SEric Dumazet 		if (in_dev)
9131da177e4SLinus Torvalds 			ip_mc_dec_group(in_dev, t->parms.iph.daddr);
9141da177e4SLinus Torvalds 	}
9151da177e4SLinus Torvalds 	return 0;
9161da177e4SLinus Torvalds }
9171da177e4SLinus Torvalds #endif
9181da177e4SLinus Torvalds 
919b8c26a33SStephen Hemminger static const struct net_device_ops ipgre_netdev_ops = {
920b8c26a33SStephen Hemminger 	.ndo_init		= ipgre_tunnel_init,
921c5441932SPravin B Shelar 	.ndo_uninit		= ip_tunnel_uninit,
922b8c26a33SStephen Hemminger #ifdef CONFIG_NET_IPGRE_BROADCAST
923b8c26a33SStephen Hemminger 	.ndo_open		= ipgre_open,
924b8c26a33SStephen Hemminger 	.ndo_stop		= ipgre_close,
925b8c26a33SStephen Hemminger #endif
926c5441932SPravin B Shelar 	.ndo_start_xmit		= ipgre_xmit,
927b8c26a33SStephen Hemminger 	.ndo_do_ioctl		= ipgre_tunnel_ioctl,
928c5441932SPravin B Shelar 	.ndo_change_mtu		= ip_tunnel_change_mtu,
929c5441932SPravin B Shelar 	.ndo_get_stats64	= ip_tunnel_get_stats64,
9301e99584bSNicolas Dichtel 	.ndo_get_iflink		= ip_tunnel_get_iflink,
931b8c26a33SStephen Hemminger };
932b8c26a33SStephen Hemminger 
9336b78f16eSEric Dumazet #define GRE_FEATURES (NETIF_F_SG |		\
9346b78f16eSEric Dumazet 		      NETIF_F_FRAGLIST |	\
9356b78f16eSEric Dumazet 		      NETIF_F_HIGHDMA |		\
9366b78f16eSEric Dumazet 		      NETIF_F_HW_CSUM)
9376b78f16eSEric Dumazet 
9381da177e4SLinus Torvalds static void ipgre_tunnel_setup(struct net_device *dev)
9391da177e4SLinus Torvalds {
940b8c26a33SStephen Hemminger 	dev->netdev_ops		= &ipgre_netdev_ops;
9415a455275SNicolas Dichtel 	dev->type		= ARPHRD_IPGRE;
942c5441932SPravin B Shelar 	ip_tunnel_setup(dev, ipgre_net_id);
943c5441932SPravin B Shelar }
9441da177e4SLinus Torvalds 
945c5441932SPravin B Shelar static void __gre_tunnel_init(struct net_device *dev)
946c5441932SPravin B Shelar {
947c5441932SPravin B Shelar 	struct ip_tunnel *tunnel;
948c5441932SPravin B Shelar 
949c5441932SPravin B Shelar 	tunnel = netdev_priv(dev);
95095f5c64cSTom Herbert 	tunnel->tun_hlen = gre_calc_hlen(tunnel->parms.o_flags);
951c5441932SPravin B Shelar 	tunnel->parms.iph.protocol = IPPROTO_GRE;
952c5441932SPravin B Shelar 
9534565e991STom Herbert 	tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen;
9544565e991STom Herbert 
955b57708adSNicolas Dichtel 	dev->features		|= GRE_FEATURES;
9566b78f16eSEric Dumazet 	dev->hw_features	|= GRE_FEATURES;
957c5441932SPravin B Shelar 
958c5441932SPravin B Shelar 	if (!(tunnel->parms.o_flags & TUNNEL_SEQ)) {
959a0ca153fSAlexander Duyck 		/* TCP offload with GRE SEQ is not supported, nor
960a0ca153fSAlexander Duyck 		 * can we support 2 levels of outer headers requiring
961a0ca153fSAlexander Duyck 		 * an update.
962a0ca153fSAlexander Duyck 		 */
963a0ca153fSAlexander Duyck 		if (!(tunnel->parms.o_flags & TUNNEL_CSUM) ||
964a0ca153fSAlexander Duyck 		    (tunnel->encap.type == TUNNEL_ENCAP_NONE)) {
965c5441932SPravin B Shelar 			dev->features    |= NETIF_F_GSO_SOFTWARE;
966c5441932SPravin B Shelar 			dev->hw_features |= NETIF_F_GSO_SOFTWARE;
967a0ca153fSAlexander Duyck 		}
968a0ca153fSAlexander Duyck 
969c5441932SPravin B Shelar 		/* Can use a lockless transmit, unless we generate
970c5441932SPravin B Shelar 		 * output sequences
971c5441932SPravin B Shelar 		 */
972c5441932SPravin B Shelar 		dev->features |= NETIF_F_LLTX;
973c5441932SPravin B Shelar 	}
9741da177e4SLinus Torvalds }
9751da177e4SLinus Torvalds 
9761da177e4SLinus Torvalds static int ipgre_tunnel_init(struct net_device *dev)
9771da177e4SLinus Torvalds {
978c5441932SPravin B Shelar 	struct ip_tunnel *tunnel = netdev_priv(dev);
979c5441932SPravin B Shelar 	struct iphdr *iph = &tunnel->parms.iph;
9801da177e4SLinus Torvalds 
981c5441932SPravin B Shelar 	__gre_tunnel_init(dev);
9821da177e4SLinus Torvalds 
983c5441932SPravin B Shelar 	memcpy(dev->dev_addr, &iph->saddr, 4);
984c5441932SPravin B Shelar 	memcpy(dev->broadcast, &iph->daddr, 4);
9851da177e4SLinus Torvalds 
986c5441932SPravin B Shelar 	dev->flags		= IFF_NOARP;
98702875878SEric Dumazet 	netif_keep_dst(dev);
988c5441932SPravin B Shelar 	dev->addr_len		= 4;
9891da177e4SLinus Torvalds 
990a64b04d8SJiri Benc 	if (iph->daddr && !tunnel->collect_md) {
9911da177e4SLinus Torvalds #ifdef CONFIG_NET_IPGRE_BROADCAST
992f97c1e0cSJoe Perches 		if (ipv4_is_multicast(iph->daddr)) {
9931da177e4SLinus Torvalds 			if (!iph->saddr)
9941da177e4SLinus Torvalds 				return -EINVAL;
9951da177e4SLinus Torvalds 			dev->flags = IFF_BROADCAST;
9963b04dddeSStephen Hemminger 			dev->header_ops = &ipgre_header_ops;
9971da177e4SLinus Torvalds 		}
9981da177e4SLinus Torvalds #endif
999a64b04d8SJiri Benc 	} else if (!tunnel->collect_md) {
10006a5f44d7STimo Teras 		dev->header_ops = &ipgre_header_ops;
1001a64b04d8SJiri Benc 	}
10021da177e4SLinus Torvalds 
1003c5441932SPravin B Shelar 	return ip_tunnel_init(dev);
100460769a5dSEric Dumazet }
100560769a5dSEric Dumazet 
10069f57c67cSPravin B Shelar static const struct gre_protocol ipgre_protocol = {
10079f57c67cSPravin B Shelar 	.handler     = gre_rcv,
10089f57c67cSPravin B Shelar 	.err_handler = gre_err,
10091da177e4SLinus Torvalds };
10101da177e4SLinus Torvalds 
10112c8c1e72SAlexey Dobriyan static int __net_init ipgre_init_net(struct net *net)
101259a4c759SPavel Emelyanov {
1013c5441932SPravin B Shelar 	return ip_tunnel_init_net(net, ipgre_net_id, &ipgre_link_ops, NULL);
101459a4c759SPavel Emelyanov }
101559a4c759SPavel Emelyanov 
101664bc1781SEric Dumazet static void __net_exit ipgre_exit_batch_net(struct list_head *list_net)
101759a4c759SPavel Emelyanov {
101864bc1781SEric Dumazet 	ip_tunnel_delete_nets(list_net, ipgre_net_id, &ipgre_link_ops);
101959a4c759SPavel Emelyanov }
102059a4c759SPavel Emelyanov 
102159a4c759SPavel Emelyanov static struct pernet_operations ipgre_net_ops = {
102259a4c759SPavel Emelyanov 	.init = ipgre_init_net,
102364bc1781SEric Dumazet 	.exit_batch = ipgre_exit_batch_net,
1024cfb8fbf2SEric W. Biederman 	.id   = &ipgre_net_id,
1025c5441932SPravin B Shelar 	.size = sizeof(struct ip_tunnel_net),
102659a4c759SPavel Emelyanov };
10271da177e4SLinus Torvalds 
1028a8b8a889SMatthias Schiffer static int ipgre_tunnel_validate(struct nlattr *tb[], struct nlattr *data[],
1029a8b8a889SMatthias Schiffer 				 struct netlink_ext_ack *extack)
1030c19e654dSHerbert Xu {
1031c19e654dSHerbert Xu 	__be16 flags;
1032c19e654dSHerbert Xu 
1033c19e654dSHerbert Xu 	if (!data)
1034c19e654dSHerbert Xu 		return 0;
1035c19e654dSHerbert Xu 
1036c19e654dSHerbert Xu 	flags = 0;
1037c19e654dSHerbert Xu 	if (data[IFLA_GRE_IFLAGS])
1038c19e654dSHerbert Xu 		flags |= nla_get_be16(data[IFLA_GRE_IFLAGS]);
1039c19e654dSHerbert Xu 	if (data[IFLA_GRE_OFLAGS])
1040c19e654dSHerbert Xu 		flags |= nla_get_be16(data[IFLA_GRE_OFLAGS]);
1041c19e654dSHerbert Xu 	if (flags & (GRE_VERSION|GRE_ROUTING))
1042c19e654dSHerbert Xu 		return -EINVAL;
1043c19e654dSHerbert Xu 
1044946b636fSJiri Benc 	if (data[IFLA_GRE_COLLECT_METADATA] &&
1045946b636fSJiri Benc 	    data[IFLA_GRE_ENCAP_TYPE] &&
1046946b636fSJiri Benc 	    nla_get_u16(data[IFLA_GRE_ENCAP_TYPE]) != TUNNEL_ENCAP_NONE)
1047946b636fSJiri Benc 		return -EINVAL;
1048946b636fSJiri Benc 
1049c19e654dSHerbert Xu 	return 0;
1050c19e654dSHerbert Xu }
1051c19e654dSHerbert Xu 
1052a8b8a889SMatthias Schiffer static int ipgre_tap_validate(struct nlattr *tb[], struct nlattr *data[],
1053a8b8a889SMatthias Schiffer 			      struct netlink_ext_ack *extack)
1054e1a80002SHerbert Xu {
1055e1a80002SHerbert Xu 	__be32 daddr;
1056e1a80002SHerbert Xu 
1057e1a80002SHerbert Xu 	if (tb[IFLA_ADDRESS]) {
1058e1a80002SHerbert Xu 		if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN)
1059e1a80002SHerbert Xu 			return -EINVAL;
1060e1a80002SHerbert Xu 		if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS])))
1061e1a80002SHerbert Xu 			return -EADDRNOTAVAIL;
1062e1a80002SHerbert Xu 	}
1063e1a80002SHerbert Xu 
1064e1a80002SHerbert Xu 	if (!data)
1065e1a80002SHerbert Xu 		goto out;
1066e1a80002SHerbert Xu 
1067e1a80002SHerbert Xu 	if (data[IFLA_GRE_REMOTE]) {
1068e1a80002SHerbert Xu 		memcpy(&daddr, nla_data(data[IFLA_GRE_REMOTE]), 4);
1069e1a80002SHerbert Xu 		if (!daddr)
1070e1a80002SHerbert Xu 			return -EINVAL;
1071e1a80002SHerbert Xu 	}
1072e1a80002SHerbert Xu 
1073e1a80002SHerbert Xu out:
1074a8b8a889SMatthias Schiffer 	return ipgre_tunnel_validate(tb, data, extack);
1075e1a80002SHerbert Xu }
1076e1a80002SHerbert Xu 
107784e54fe0SWilliam Tu static int erspan_validate(struct nlattr *tb[], struct nlattr *data[],
107884e54fe0SWilliam Tu 			   struct netlink_ext_ack *extack)
107984e54fe0SWilliam Tu {
108084e54fe0SWilliam Tu 	__be16 flags = 0;
108184e54fe0SWilliam Tu 	int ret;
108284e54fe0SWilliam Tu 
108384e54fe0SWilliam Tu 	if (!data)
108484e54fe0SWilliam Tu 		return 0;
108584e54fe0SWilliam Tu 
108684e54fe0SWilliam Tu 	ret = ipgre_tap_validate(tb, data, extack);
108784e54fe0SWilliam Tu 	if (ret)
108884e54fe0SWilliam Tu 		return ret;
108984e54fe0SWilliam Tu 
1090*51fa960dSWilliam Tu 	if (data[IFLA_GRE_ERSPAN_VER] &&
1091*51fa960dSWilliam Tu 	    nla_get_u8(data[IFLA_GRE_ERSPAN_VER]) == 0)
1092f989d546SWilliam Tu 		return 0;
1093f989d546SWilliam Tu 
1094f989d546SWilliam Tu 	/* ERSPAN type II/III should only have GRE sequence and key flag */
10951a66a836SWilliam Tu 	if (data[IFLA_GRE_OFLAGS])
109684e54fe0SWilliam Tu 		flags |= nla_get_be16(data[IFLA_GRE_OFLAGS]);
10971a66a836SWilliam Tu 	if (data[IFLA_GRE_IFLAGS])
109884e54fe0SWilliam Tu 		flags |= nla_get_be16(data[IFLA_GRE_IFLAGS]);
10991a66a836SWilliam Tu 	if (!data[IFLA_GRE_COLLECT_METADATA] &&
11001a66a836SWilliam Tu 	    flags != (GRE_SEQ | GRE_KEY))
110184e54fe0SWilliam Tu 		return -EINVAL;
110284e54fe0SWilliam Tu 
110384e54fe0SWilliam Tu 	/* ERSPAN Session ID only has 10-bit. Since we reuse
110484e54fe0SWilliam Tu 	 * 32-bit key field as ID, check it's range.
110584e54fe0SWilliam Tu 	 */
110684e54fe0SWilliam Tu 	if (data[IFLA_GRE_IKEY] &&
110784e54fe0SWilliam Tu 	    (ntohl(nla_get_be32(data[IFLA_GRE_IKEY])) & ~ID_MASK))
110884e54fe0SWilliam Tu 		return -EINVAL;
110984e54fe0SWilliam Tu 
111084e54fe0SWilliam Tu 	if (data[IFLA_GRE_OKEY] &&
111184e54fe0SWilliam Tu 	    (ntohl(nla_get_be32(data[IFLA_GRE_OKEY])) & ~ID_MASK))
111284e54fe0SWilliam Tu 		return -EINVAL;
111384e54fe0SWilliam Tu 
111484e54fe0SWilliam Tu 	return 0;
111584e54fe0SWilliam Tu }
111684e54fe0SWilliam Tu 
111722a59be8SPhilip Prindeville static int ipgre_netlink_parms(struct net_device *dev,
11182e15ea39SPravin B Shelar 				struct nlattr *data[],
11192e15ea39SPravin B Shelar 				struct nlattr *tb[],
11209830ad4cSCraig Gallek 				struct ip_tunnel_parm *parms,
11219830ad4cSCraig Gallek 				__u32 *fwmark)
1122c19e654dSHerbert Xu {
112322a59be8SPhilip Prindeville 	struct ip_tunnel *t = netdev_priv(dev);
112422a59be8SPhilip Prindeville 
11257bb82d92SHerbert Xu 	memset(parms, 0, sizeof(*parms));
1126c19e654dSHerbert Xu 
1127c19e654dSHerbert Xu 	parms->iph.protocol = IPPROTO_GRE;
1128c19e654dSHerbert Xu 
1129c19e654dSHerbert Xu 	if (!data)
113022a59be8SPhilip Prindeville 		return 0;
1131c19e654dSHerbert Xu 
1132c19e654dSHerbert Xu 	if (data[IFLA_GRE_LINK])
1133c19e654dSHerbert Xu 		parms->link = nla_get_u32(data[IFLA_GRE_LINK]);
1134c19e654dSHerbert Xu 
1135c19e654dSHerbert Xu 	if (data[IFLA_GRE_IFLAGS])
1136c5441932SPravin B Shelar 		parms->i_flags = gre_flags_to_tnl_flags(nla_get_be16(data[IFLA_GRE_IFLAGS]));
1137c19e654dSHerbert Xu 
1138c19e654dSHerbert Xu 	if (data[IFLA_GRE_OFLAGS])
1139c5441932SPravin B Shelar 		parms->o_flags = gre_flags_to_tnl_flags(nla_get_be16(data[IFLA_GRE_OFLAGS]));
1140c19e654dSHerbert Xu 
1141c19e654dSHerbert Xu 	if (data[IFLA_GRE_IKEY])
1142c19e654dSHerbert Xu 		parms->i_key = nla_get_be32(data[IFLA_GRE_IKEY]);
1143c19e654dSHerbert Xu 
1144c19e654dSHerbert Xu 	if (data[IFLA_GRE_OKEY])
1145c19e654dSHerbert Xu 		parms->o_key = nla_get_be32(data[IFLA_GRE_OKEY]);
1146c19e654dSHerbert Xu 
1147c19e654dSHerbert Xu 	if (data[IFLA_GRE_LOCAL])
114867b61f6cSJiri Benc 		parms->iph.saddr = nla_get_in_addr(data[IFLA_GRE_LOCAL]);
1149c19e654dSHerbert Xu 
1150c19e654dSHerbert Xu 	if (data[IFLA_GRE_REMOTE])
115167b61f6cSJiri Benc 		parms->iph.daddr = nla_get_in_addr(data[IFLA_GRE_REMOTE]);
1152c19e654dSHerbert Xu 
1153c19e654dSHerbert Xu 	if (data[IFLA_GRE_TTL])
1154c19e654dSHerbert Xu 		parms->iph.ttl = nla_get_u8(data[IFLA_GRE_TTL]);
1155c19e654dSHerbert Xu 
1156c19e654dSHerbert Xu 	if (data[IFLA_GRE_TOS])
1157c19e654dSHerbert Xu 		parms->iph.tos = nla_get_u8(data[IFLA_GRE_TOS]);
1158c19e654dSHerbert Xu 
115922a59be8SPhilip Prindeville 	if (!data[IFLA_GRE_PMTUDISC] || nla_get_u8(data[IFLA_GRE_PMTUDISC])) {
116022a59be8SPhilip Prindeville 		if (t->ignore_df)
116122a59be8SPhilip Prindeville 			return -EINVAL;
1162c19e654dSHerbert Xu 		parms->iph.frag_off = htons(IP_DF);
116322a59be8SPhilip Prindeville 	}
11642e15ea39SPravin B Shelar 
11652e15ea39SPravin B Shelar 	if (data[IFLA_GRE_COLLECT_METADATA]) {
11662e15ea39SPravin B Shelar 		t->collect_md = true;
1167e271c7b4SJiri Benc 		if (dev->type == ARPHRD_IPGRE)
1168e271c7b4SJiri Benc 			dev->type = ARPHRD_NONE;
11692e15ea39SPravin B Shelar 	}
117022a59be8SPhilip Prindeville 
117122a59be8SPhilip Prindeville 	if (data[IFLA_GRE_IGNORE_DF]) {
117222a59be8SPhilip Prindeville 		if (nla_get_u8(data[IFLA_GRE_IGNORE_DF])
117322a59be8SPhilip Prindeville 		  && (parms->iph.frag_off & htons(IP_DF)))
117422a59be8SPhilip Prindeville 			return -EINVAL;
117522a59be8SPhilip Prindeville 		t->ignore_df = !!nla_get_u8(data[IFLA_GRE_IGNORE_DF]);
117622a59be8SPhilip Prindeville 	}
117722a59be8SPhilip Prindeville 
11789830ad4cSCraig Gallek 	if (data[IFLA_GRE_FWMARK])
11799830ad4cSCraig Gallek 		*fwmark = nla_get_u32(data[IFLA_GRE_FWMARK]);
11809830ad4cSCraig Gallek 
1181e1f8f78fSPetr Machata 	return 0;
1182e1f8f78fSPetr Machata }
1183e1f8f78fSPetr Machata 
1184e1f8f78fSPetr Machata static int erspan_netlink_parms(struct net_device *dev,
1185e1f8f78fSPetr Machata 				struct nlattr *data[],
1186e1f8f78fSPetr Machata 				struct nlattr *tb[],
1187e1f8f78fSPetr Machata 				struct ip_tunnel_parm *parms,
1188e1f8f78fSPetr Machata 				__u32 *fwmark)
1189e1f8f78fSPetr Machata {
1190e1f8f78fSPetr Machata 	struct ip_tunnel *t = netdev_priv(dev);
1191e1f8f78fSPetr Machata 	int err;
1192e1f8f78fSPetr Machata 
1193e1f8f78fSPetr Machata 	err = ipgre_netlink_parms(dev, data, tb, parms, fwmark);
1194e1f8f78fSPetr Machata 	if (err)
1195e1f8f78fSPetr Machata 		return err;
119632ca98feSPetr Machata 	if (!data)
119732ca98feSPetr Machata 		return 0;
1198e1f8f78fSPetr Machata 
1199f551c91dSWilliam Tu 	if (data[IFLA_GRE_ERSPAN_VER]) {
1200f551c91dSWilliam Tu 		t->erspan_ver = nla_get_u8(data[IFLA_GRE_ERSPAN_VER]);
1201f551c91dSWilliam Tu 
1202f989d546SWilliam Tu 		if (t->erspan_ver > 2)
1203f551c91dSWilliam Tu 			return -EINVAL;
1204f551c91dSWilliam Tu 	}
1205f551c91dSWilliam Tu 
1206f551c91dSWilliam Tu 	if (t->erspan_ver == 1) {
120784e54fe0SWilliam Tu 		if (data[IFLA_GRE_ERSPAN_INDEX]) {
120884e54fe0SWilliam Tu 			t->index = nla_get_u32(data[IFLA_GRE_ERSPAN_INDEX]);
120984e54fe0SWilliam Tu 			if (t->index & ~INDEX_MASK)
121084e54fe0SWilliam Tu 				return -EINVAL;
121184e54fe0SWilliam Tu 		}
1212f551c91dSWilliam Tu 	} else if (t->erspan_ver == 2) {
1213f551c91dSWilliam Tu 		if (data[IFLA_GRE_ERSPAN_DIR]) {
1214f551c91dSWilliam Tu 			t->dir = nla_get_u8(data[IFLA_GRE_ERSPAN_DIR]);
1215f551c91dSWilliam Tu 			if (t->dir & ~(DIR_MASK >> DIR_OFFSET))
1216f551c91dSWilliam Tu 				return -EINVAL;
1217f551c91dSWilliam Tu 		}
1218f551c91dSWilliam Tu 		if (data[IFLA_GRE_ERSPAN_HWID]) {
1219f551c91dSWilliam Tu 			t->hwid = nla_get_u16(data[IFLA_GRE_ERSPAN_HWID]);
1220f551c91dSWilliam Tu 			if (t->hwid & ~(HWID_MASK >> HWID_OFFSET))
1221f551c91dSWilliam Tu 				return -EINVAL;
1222f551c91dSWilliam Tu 		}
1223f551c91dSWilliam Tu 	}
122484e54fe0SWilliam Tu 
122522a59be8SPhilip Prindeville 	return 0;
1226c19e654dSHerbert Xu }
1227c19e654dSHerbert Xu 
12284565e991STom Herbert /* This function returns true when ENCAP attributes are present in the nl msg */
12294565e991STom Herbert static bool ipgre_netlink_encap_parms(struct nlattr *data[],
12304565e991STom Herbert 				      struct ip_tunnel_encap *ipencap)
12314565e991STom Herbert {
12324565e991STom Herbert 	bool ret = false;
12334565e991STom Herbert 
12344565e991STom Herbert 	memset(ipencap, 0, sizeof(*ipencap));
12354565e991STom Herbert 
12364565e991STom Herbert 	if (!data)
12374565e991STom Herbert 		return ret;
12384565e991STom Herbert 
12394565e991STom Herbert 	if (data[IFLA_GRE_ENCAP_TYPE]) {
12404565e991STom Herbert 		ret = true;
12414565e991STom Herbert 		ipencap->type = nla_get_u16(data[IFLA_GRE_ENCAP_TYPE]);
12424565e991STom Herbert 	}
12434565e991STom Herbert 
12444565e991STom Herbert 	if (data[IFLA_GRE_ENCAP_FLAGS]) {
12454565e991STom Herbert 		ret = true;
12464565e991STom Herbert 		ipencap->flags = nla_get_u16(data[IFLA_GRE_ENCAP_FLAGS]);
12474565e991STom Herbert 	}
12484565e991STom Herbert 
12494565e991STom Herbert 	if (data[IFLA_GRE_ENCAP_SPORT]) {
12504565e991STom Herbert 		ret = true;
12513e97fa70SSabrina Dubroca 		ipencap->sport = nla_get_be16(data[IFLA_GRE_ENCAP_SPORT]);
12524565e991STom Herbert 	}
12534565e991STom Herbert 
12544565e991STom Herbert 	if (data[IFLA_GRE_ENCAP_DPORT]) {
12554565e991STom Herbert 		ret = true;
12563e97fa70SSabrina Dubroca 		ipencap->dport = nla_get_be16(data[IFLA_GRE_ENCAP_DPORT]);
12574565e991STom Herbert 	}
12584565e991STom Herbert 
12594565e991STom Herbert 	return ret;
12604565e991STom Herbert }
12614565e991STom Herbert 
1262c5441932SPravin B Shelar static int gre_tap_init(struct net_device *dev)
1263e1a80002SHerbert Xu {
1264c5441932SPravin B Shelar 	__gre_tunnel_init(dev);
1265bec94d43Sstephen hemminger 	dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
1266d51711c0SXin Long 	netif_keep_dst(dev);
1267e1a80002SHerbert Xu 
1268c5441932SPravin B Shelar 	return ip_tunnel_init(dev);
1269e1a80002SHerbert Xu }
1270e1a80002SHerbert Xu 
1271c5441932SPravin B Shelar static const struct net_device_ops gre_tap_netdev_ops = {
1272c5441932SPravin B Shelar 	.ndo_init		= gre_tap_init,
1273c5441932SPravin B Shelar 	.ndo_uninit		= ip_tunnel_uninit,
1274c5441932SPravin B Shelar 	.ndo_start_xmit		= gre_tap_xmit,
1275b8c26a33SStephen Hemminger 	.ndo_set_mac_address 	= eth_mac_addr,
1276b8c26a33SStephen Hemminger 	.ndo_validate_addr	= eth_validate_addr,
1277c5441932SPravin B Shelar 	.ndo_change_mtu		= ip_tunnel_change_mtu,
1278c5441932SPravin B Shelar 	.ndo_get_stats64	= ip_tunnel_get_stats64,
12791e99584bSNicolas Dichtel 	.ndo_get_iflink		= ip_tunnel_get_iflink,
1280fc4099f1SPravin B Shelar 	.ndo_fill_metadata_dst	= gre_fill_metadata_dst,
1281b8c26a33SStephen Hemminger };
1282b8c26a33SStephen Hemminger 
128384e54fe0SWilliam Tu static int erspan_tunnel_init(struct net_device *dev)
128484e54fe0SWilliam Tu {
128584e54fe0SWilliam Tu 	struct ip_tunnel *tunnel = netdev_priv(dev);
128684e54fe0SWilliam Tu 
1287f989d546SWilliam Tu 	if (tunnel->erspan_ver == 0)
1288f989d546SWilliam Tu 		tunnel->tun_hlen = 4; /* 4-byte GRE hdr. */
1289f989d546SWilliam Tu 	else
1290f989d546SWilliam Tu 		tunnel->tun_hlen = 8; /* 8-byte GRE hdr. */
1291f989d546SWilliam Tu 
129284e54fe0SWilliam Tu 	tunnel->parms.iph.protocol = IPPROTO_GRE;
1293c122fda2SXin Long 	tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen +
1294f551c91dSWilliam Tu 		       erspan_hdr_len(tunnel->erspan_ver);
129584e54fe0SWilliam Tu 
129684e54fe0SWilliam Tu 	dev->features		|= GRE_FEATURES;
129784e54fe0SWilliam Tu 	dev->hw_features	|= GRE_FEATURES;
129884e54fe0SWilliam Tu 	dev->priv_flags		|= IFF_LIVE_ADDR_CHANGE;
1299c84bed44SXin Long 	netif_keep_dst(dev);
130084e54fe0SWilliam Tu 
130184e54fe0SWilliam Tu 	return ip_tunnel_init(dev);
130284e54fe0SWilliam Tu }
130384e54fe0SWilliam Tu 
130484e54fe0SWilliam Tu static const struct net_device_ops erspan_netdev_ops = {
130584e54fe0SWilliam Tu 	.ndo_init		= erspan_tunnel_init,
130684e54fe0SWilliam Tu 	.ndo_uninit		= ip_tunnel_uninit,
130784e54fe0SWilliam Tu 	.ndo_start_xmit		= erspan_xmit,
130884e54fe0SWilliam Tu 	.ndo_set_mac_address	= eth_mac_addr,
130984e54fe0SWilliam Tu 	.ndo_validate_addr	= eth_validate_addr,
131084e54fe0SWilliam Tu 	.ndo_change_mtu		= ip_tunnel_change_mtu,
131184e54fe0SWilliam Tu 	.ndo_get_stats64	= ip_tunnel_get_stats64,
131284e54fe0SWilliam Tu 	.ndo_get_iflink		= ip_tunnel_get_iflink,
131384e54fe0SWilliam Tu 	.ndo_fill_metadata_dst	= gre_fill_metadata_dst,
131484e54fe0SWilliam Tu };
131584e54fe0SWilliam Tu 
1316e1a80002SHerbert Xu static void ipgre_tap_setup(struct net_device *dev)
1317e1a80002SHerbert Xu {
1318e1a80002SHerbert Xu 	ether_setup(dev);
1319cfddd4c3SXin Long 	dev->max_mtu = 0;
1320c5441932SPravin B Shelar 	dev->netdev_ops	= &gre_tap_netdev_ops;
1321d13b161cSJiri Benc 	dev->priv_flags &= ~IFF_TX_SKB_SHARING;
1322f8c1b7ceSstephen hemminger 	dev->priv_flags	|= IFF_LIVE_ADDR_CHANGE;
1323c5441932SPravin B Shelar 	ip_tunnel_setup(dev, gre_tap_net_id);
1324e1a80002SHerbert Xu }
1325e1a80002SHerbert Xu 
1326e1f8f78fSPetr Machata static int
1327e1f8f78fSPetr Machata ipgre_newlink_encap_setup(struct net_device *dev, struct nlattr *data[])
1328c19e654dSHerbert Xu {
13294565e991STom Herbert 	struct ip_tunnel_encap ipencap;
13304565e991STom Herbert 
13314565e991STom Herbert 	if (ipgre_netlink_encap_parms(data, &ipencap)) {
13324565e991STom Herbert 		struct ip_tunnel *t = netdev_priv(dev);
1333e1f8f78fSPetr Machata 		int err = ip_tunnel_encap_setup(t, &ipencap);
13344565e991STom Herbert 
13354565e991STom Herbert 		if (err < 0)
13364565e991STom Herbert 			return err;
13374565e991STom Herbert 	}
1338c19e654dSHerbert Xu 
1339e1f8f78fSPetr Machata 	return 0;
1340e1f8f78fSPetr Machata }
1341e1f8f78fSPetr Machata 
1342e1f8f78fSPetr Machata static int ipgre_newlink(struct net *src_net, struct net_device *dev,
1343e1f8f78fSPetr Machata 			 struct nlattr *tb[], struct nlattr *data[],
1344e1f8f78fSPetr Machata 			 struct netlink_ext_ack *extack)
1345e1f8f78fSPetr Machata {
1346e1f8f78fSPetr Machata 	struct ip_tunnel_parm p;
1347e1f8f78fSPetr Machata 	__u32 fwmark = 0;
1348e1f8f78fSPetr Machata 	int err;
1349e1f8f78fSPetr Machata 
1350e1f8f78fSPetr Machata 	err = ipgre_newlink_encap_setup(dev, data);
1351e1f8f78fSPetr Machata 	if (err)
1352e1f8f78fSPetr Machata 		return err;
1353e1f8f78fSPetr Machata 
13549830ad4cSCraig Gallek 	err = ipgre_netlink_parms(dev, data, tb, &p, &fwmark);
135522a59be8SPhilip Prindeville 	if (err < 0)
135622a59be8SPhilip Prindeville 		return err;
13579830ad4cSCraig Gallek 	return ip_tunnel_newlink(dev, tb, &p, fwmark);
1358c19e654dSHerbert Xu }
1359c19e654dSHerbert Xu 
1360e1f8f78fSPetr Machata static int erspan_newlink(struct net *src_net, struct net_device *dev,
1361e1f8f78fSPetr Machata 			  struct nlattr *tb[], struct nlattr *data[],
1362e1f8f78fSPetr Machata 			  struct netlink_ext_ack *extack)
1363e1f8f78fSPetr Machata {
1364e1f8f78fSPetr Machata 	struct ip_tunnel_parm p;
1365e1f8f78fSPetr Machata 	__u32 fwmark = 0;
1366e1f8f78fSPetr Machata 	int err;
1367e1f8f78fSPetr Machata 
1368e1f8f78fSPetr Machata 	err = ipgre_newlink_encap_setup(dev, data);
1369e1f8f78fSPetr Machata 	if (err)
1370e1f8f78fSPetr Machata 		return err;
1371e1f8f78fSPetr Machata 
1372e1f8f78fSPetr Machata 	err = erspan_netlink_parms(dev, data, tb, &p, &fwmark);
1373e1f8f78fSPetr Machata 	if (err)
1374e1f8f78fSPetr Machata 		return err;
1375e1f8f78fSPetr Machata 	return ip_tunnel_newlink(dev, tb, &p, fwmark);
1376e1f8f78fSPetr Machata }
1377e1f8f78fSPetr Machata 
1378c19e654dSHerbert Xu static int ipgre_changelink(struct net_device *dev, struct nlattr *tb[],
1379ad744b22SMatthias Schiffer 			    struct nlattr *data[],
1380ad744b22SMatthias Schiffer 			    struct netlink_ext_ack *extack)
1381c19e654dSHerbert Xu {
13829830ad4cSCraig Gallek 	struct ip_tunnel *t = netdev_priv(dev);
13839830ad4cSCraig Gallek 	__u32 fwmark = t->fwmark;
1384dd9d598cSXin Long 	struct ip_tunnel_parm p;
138522a59be8SPhilip Prindeville 	int err;
13864565e991STom Herbert 
1387e1f8f78fSPetr Machata 	err = ipgre_newlink_encap_setup(dev, data);
1388e1f8f78fSPetr Machata 	if (err)
13894565e991STom Herbert 		return err;
1390c19e654dSHerbert Xu 
13919830ad4cSCraig Gallek 	err = ipgre_netlink_parms(dev, data, tb, &p, &fwmark);
139222a59be8SPhilip Prindeville 	if (err < 0)
139322a59be8SPhilip Prindeville 		return err;
1394dd9d598cSXin Long 
1395dd9d598cSXin Long 	err = ip_tunnel_changelink(dev, tb, &p, fwmark);
1396dd9d598cSXin Long 	if (err < 0)
1397dd9d598cSXin Long 		return err;
1398dd9d598cSXin Long 
1399dd9d598cSXin Long 	t->parms.i_flags = p.i_flags;
1400dd9d598cSXin Long 	t->parms.o_flags = p.o_flags;
1401dd9d598cSXin Long 
1402dd9d598cSXin Long 	ipgre_link_update(dev, !tb[IFLA_MTU]);
1403dd9d598cSXin Long 
1404dd9d598cSXin Long 	return 0;
1405c19e654dSHerbert Xu }
1406c19e654dSHerbert Xu 
1407e1f8f78fSPetr Machata static int erspan_changelink(struct net_device *dev, struct nlattr *tb[],
1408e1f8f78fSPetr Machata 			     struct nlattr *data[],
1409e1f8f78fSPetr Machata 			     struct netlink_ext_ack *extack)
1410e1f8f78fSPetr Machata {
1411e1f8f78fSPetr Machata 	struct ip_tunnel *t = netdev_priv(dev);
1412e1f8f78fSPetr Machata 	__u32 fwmark = t->fwmark;
1413e1f8f78fSPetr Machata 	struct ip_tunnel_parm p;
1414e1f8f78fSPetr Machata 	int err;
1415e1f8f78fSPetr Machata 
1416e1f8f78fSPetr Machata 	err = ipgre_newlink_encap_setup(dev, data);
1417e1f8f78fSPetr Machata 	if (err)
1418e1f8f78fSPetr Machata 		return err;
1419e1f8f78fSPetr Machata 
1420e1f8f78fSPetr Machata 	err = erspan_netlink_parms(dev, data, tb, &p, &fwmark);
1421e1f8f78fSPetr Machata 	if (err < 0)
1422e1f8f78fSPetr Machata 		return err;
1423e1f8f78fSPetr Machata 
1424e1f8f78fSPetr Machata 	err = ip_tunnel_changelink(dev, tb, &p, fwmark);
1425e1f8f78fSPetr Machata 	if (err < 0)
1426e1f8f78fSPetr Machata 		return err;
1427e1f8f78fSPetr Machata 
1428e1f8f78fSPetr Machata 	t->parms.i_flags = p.i_flags;
1429e1f8f78fSPetr Machata 	t->parms.o_flags = p.o_flags;
1430e1f8f78fSPetr Machata 
1431e1f8f78fSPetr Machata 	return 0;
1432e1f8f78fSPetr Machata }
1433e1f8f78fSPetr Machata 
1434c19e654dSHerbert Xu static size_t ipgre_get_size(const struct net_device *dev)
1435c19e654dSHerbert Xu {
1436c19e654dSHerbert Xu 	return
1437c19e654dSHerbert Xu 		/* IFLA_GRE_LINK */
1438c19e654dSHerbert Xu 		nla_total_size(4) +
1439c19e654dSHerbert Xu 		/* IFLA_GRE_IFLAGS */
1440c19e654dSHerbert Xu 		nla_total_size(2) +
1441c19e654dSHerbert Xu 		/* IFLA_GRE_OFLAGS */
1442c19e654dSHerbert Xu 		nla_total_size(2) +
1443c19e654dSHerbert Xu 		/* IFLA_GRE_IKEY */
1444c19e654dSHerbert Xu 		nla_total_size(4) +
1445c19e654dSHerbert Xu 		/* IFLA_GRE_OKEY */
1446c19e654dSHerbert Xu 		nla_total_size(4) +
1447c19e654dSHerbert Xu 		/* IFLA_GRE_LOCAL */
1448c19e654dSHerbert Xu 		nla_total_size(4) +
1449c19e654dSHerbert Xu 		/* IFLA_GRE_REMOTE */
1450c19e654dSHerbert Xu 		nla_total_size(4) +
1451c19e654dSHerbert Xu 		/* IFLA_GRE_TTL */
1452c19e654dSHerbert Xu 		nla_total_size(1) +
1453c19e654dSHerbert Xu 		/* IFLA_GRE_TOS */
1454c19e654dSHerbert Xu 		nla_total_size(1) +
1455c19e654dSHerbert Xu 		/* IFLA_GRE_PMTUDISC */
1456c19e654dSHerbert Xu 		nla_total_size(1) +
14574565e991STom Herbert 		/* IFLA_GRE_ENCAP_TYPE */
14584565e991STom Herbert 		nla_total_size(2) +
14594565e991STom Herbert 		/* IFLA_GRE_ENCAP_FLAGS */
14604565e991STom Herbert 		nla_total_size(2) +
14614565e991STom Herbert 		/* IFLA_GRE_ENCAP_SPORT */
14624565e991STom Herbert 		nla_total_size(2) +
14634565e991STom Herbert 		/* IFLA_GRE_ENCAP_DPORT */
14644565e991STom Herbert 		nla_total_size(2) +
14652e15ea39SPravin B Shelar 		/* IFLA_GRE_COLLECT_METADATA */
14662e15ea39SPravin B Shelar 		nla_total_size(0) +
146722a59be8SPhilip Prindeville 		/* IFLA_GRE_IGNORE_DF */
146822a59be8SPhilip Prindeville 		nla_total_size(1) +
14699830ad4cSCraig Gallek 		/* IFLA_GRE_FWMARK */
14709830ad4cSCraig Gallek 		nla_total_size(4) +
147184e54fe0SWilliam Tu 		/* IFLA_GRE_ERSPAN_INDEX */
147284e54fe0SWilliam Tu 		nla_total_size(4) +
1473f551c91dSWilliam Tu 		/* IFLA_GRE_ERSPAN_VER */
1474f551c91dSWilliam Tu 		nla_total_size(1) +
1475f551c91dSWilliam Tu 		/* IFLA_GRE_ERSPAN_DIR */
1476f551c91dSWilliam Tu 		nla_total_size(1) +
1477f551c91dSWilliam Tu 		/* IFLA_GRE_ERSPAN_HWID */
1478f551c91dSWilliam Tu 		nla_total_size(2) +
1479c19e654dSHerbert Xu 		0;
1480c19e654dSHerbert Xu }
1481c19e654dSHerbert Xu 
1482c19e654dSHerbert Xu static int ipgre_fill_info(struct sk_buff *skb, const struct net_device *dev)
1483c19e654dSHerbert Xu {
1484c19e654dSHerbert Xu 	struct ip_tunnel *t = netdev_priv(dev);
1485c19e654dSHerbert Xu 	struct ip_tunnel_parm *p = &t->parms;
1486feaf5c79SLorenzo Bianconi 	__be16 o_flags = p->o_flags;
1487feaf5c79SLorenzo Bianconi 
1488f989d546SWilliam Tu 	if (t->erspan_ver <= 2) {
1489f989d546SWilliam Tu 		if (t->erspan_ver != 0 && !t->collect_md)
1490feaf5c79SLorenzo Bianconi 			o_flags |= TUNNEL_KEY;
1491c19e654dSHerbert Xu 
14922bdf700eSLorenzo Bianconi 		if (nla_put_u8(skb, IFLA_GRE_ERSPAN_VER, t->erspan_ver))
14932bdf700eSLorenzo Bianconi 			goto nla_put_failure;
14942bdf700eSLorenzo Bianconi 
14952bdf700eSLorenzo Bianconi 		if (t->erspan_ver == 1) {
14962bdf700eSLorenzo Bianconi 			if (nla_put_u32(skb, IFLA_GRE_ERSPAN_INDEX, t->index))
14972bdf700eSLorenzo Bianconi 				goto nla_put_failure;
1498f989d546SWilliam Tu 		} else if (t->erspan_ver == 2) {
14992bdf700eSLorenzo Bianconi 			if (nla_put_u8(skb, IFLA_GRE_ERSPAN_DIR, t->dir))
15002bdf700eSLorenzo Bianconi 				goto nla_put_failure;
15012bdf700eSLorenzo Bianconi 			if (nla_put_u16(skb, IFLA_GRE_ERSPAN_HWID, t->hwid))
15022bdf700eSLorenzo Bianconi 				goto nla_put_failure;
15032bdf700eSLorenzo Bianconi 		}
15042bdf700eSLorenzo Bianconi 	}
15052bdf700eSLorenzo Bianconi 
1506f3756b79SDavid S. Miller 	if (nla_put_u32(skb, IFLA_GRE_LINK, p->link) ||
150795f5c64cSTom Herbert 	    nla_put_be16(skb, IFLA_GRE_IFLAGS,
150895f5c64cSTom Herbert 			 gre_tnl_flags_to_gre_flags(p->i_flags)) ||
150995f5c64cSTom Herbert 	    nla_put_be16(skb, IFLA_GRE_OFLAGS,
1510feaf5c79SLorenzo Bianconi 			 gre_tnl_flags_to_gre_flags(o_flags)) ||
1511f3756b79SDavid S. Miller 	    nla_put_be32(skb, IFLA_GRE_IKEY, p->i_key) ||
1512f3756b79SDavid S. Miller 	    nla_put_be32(skb, IFLA_GRE_OKEY, p->o_key) ||
1513930345eaSJiri Benc 	    nla_put_in_addr(skb, IFLA_GRE_LOCAL, p->iph.saddr) ||
1514930345eaSJiri Benc 	    nla_put_in_addr(skb, IFLA_GRE_REMOTE, p->iph.daddr) ||
1515f3756b79SDavid S. Miller 	    nla_put_u8(skb, IFLA_GRE_TTL, p->iph.ttl) ||
1516f3756b79SDavid S. Miller 	    nla_put_u8(skb, IFLA_GRE_TOS, p->iph.tos) ||
1517f3756b79SDavid S. Miller 	    nla_put_u8(skb, IFLA_GRE_PMTUDISC,
15189830ad4cSCraig Gallek 		       !!(p->iph.frag_off & htons(IP_DF))) ||
15199830ad4cSCraig Gallek 	    nla_put_u32(skb, IFLA_GRE_FWMARK, t->fwmark))
1520f3756b79SDavid S. Miller 		goto nla_put_failure;
15214565e991STom Herbert 
15224565e991STom Herbert 	if (nla_put_u16(skb, IFLA_GRE_ENCAP_TYPE,
15234565e991STom Herbert 			t->encap.type) ||
15243e97fa70SSabrina Dubroca 	    nla_put_be16(skb, IFLA_GRE_ENCAP_SPORT,
15254565e991STom Herbert 			 t->encap.sport) ||
15263e97fa70SSabrina Dubroca 	    nla_put_be16(skb, IFLA_GRE_ENCAP_DPORT,
15274565e991STom Herbert 			 t->encap.dport) ||
15284565e991STom Herbert 	    nla_put_u16(skb, IFLA_GRE_ENCAP_FLAGS,
1529e1b2cb65STom Herbert 			t->encap.flags))
15304565e991STom Herbert 		goto nla_put_failure;
15314565e991STom Herbert 
153222a59be8SPhilip Prindeville 	if (nla_put_u8(skb, IFLA_GRE_IGNORE_DF, t->ignore_df))
153322a59be8SPhilip Prindeville 		goto nla_put_failure;
153422a59be8SPhilip Prindeville 
15352e15ea39SPravin B Shelar 	if (t->collect_md) {
15362e15ea39SPravin B Shelar 		if (nla_put_flag(skb, IFLA_GRE_COLLECT_METADATA))
15372e15ea39SPravin B Shelar 			goto nla_put_failure;
15382e15ea39SPravin B Shelar 	}
15392e15ea39SPravin B Shelar 
1540c19e654dSHerbert Xu 	return 0;
1541c19e654dSHerbert Xu 
1542c19e654dSHerbert Xu nla_put_failure:
1543c19e654dSHerbert Xu 	return -EMSGSIZE;
1544c19e654dSHerbert Xu }
1545c19e654dSHerbert Xu 
154684e54fe0SWilliam Tu static void erspan_setup(struct net_device *dev)
154784e54fe0SWilliam Tu {
154884581bdaSXin Long 	struct ip_tunnel *t = netdev_priv(dev);
154984581bdaSXin Long 
155084e54fe0SWilliam Tu 	ether_setup(dev);
15510e141f75SHaishuang Yan 	dev->max_mtu = 0;
155284e54fe0SWilliam Tu 	dev->netdev_ops = &erspan_netdev_ops;
155384e54fe0SWilliam Tu 	dev->priv_flags &= ~IFF_TX_SKB_SHARING;
155484e54fe0SWilliam Tu 	dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
155584e54fe0SWilliam Tu 	ip_tunnel_setup(dev, erspan_net_id);
155684581bdaSXin Long 	t->erspan_ver = 1;
155784e54fe0SWilliam Tu }
155884e54fe0SWilliam Tu 
1559c19e654dSHerbert Xu static const struct nla_policy ipgre_policy[IFLA_GRE_MAX + 1] = {
1560c19e654dSHerbert Xu 	[IFLA_GRE_LINK]		= { .type = NLA_U32 },
1561c19e654dSHerbert Xu 	[IFLA_GRE_IFLAGS]	= { .type = NLA_U16 },
1562c19e654dSHerbert Xu 	[IFLA_GRE_OFLAGS]	= { .type = NLA_U16 },
1563c19e654dSHerbert Xu 	[IFLA_GRE_IKEY]		= { .type = NLA_U32 },
1564c19e654dSHerbert Xu 	[IFLA_GRE_OKEY]		= { .type = NLA_U32 },
1565c593642cSPankaj Bharadiya 	[IFLA_GRE_LOCAL]	= { .len = sizeof_field(struct iphdr, saddr) },
1566c593642cSPankaj Bharadiya 	[IFLA_GRE_REMOTE]	= { .len = sizeof_field(struct iphdr, daddr) },
1567c19e654dSHerbert Xu 	[IFLA_GRE_TTL]		= { .type = NLA_U8 },
1568c19e654dSHerbert Xu 	[IFLA_GRE_TOS]		= { .type = NLA_U8 },
1569c19e654dSHerbert Xu 	[IFLA_GRE_PMTUDISC]	= { .type = NLA_U8 },
15704565e991STom Herbert 	[IFLA_GRE_ENCAP_TYPE]	= { .type = NLA_U16 },
15714565e991STom Herbert 	[IFLA_GRE_ENCAP_FLAGS]	= { .type = NLA_U16 },
15724565e991STom Herbert 	[IFLA_GRE_ENCAP_SPORT]	= { .type = NLA_U16 },
15734565e991STom Herbert 	[IFLA_GRE_ENCAP_DPORT]	= { .type = NLA_U16 },
15742e15ea39SPravin B Shelar 	[IFLA_GRE_COLLECT_METADATA]	= { .type = NLA_FLAG },
157522a59be8SPhilip Prindeville 	[IFLA_GRE_IGNORE_DF]	= { .type = NLA_U8 },
15769830ad4cSCraig Gallek 	[IFLA_GRE_FWMARK]	= { .type = NLA_U32 },
157784e54fe0SWilliam Tu 	[IFLA_GRE_ERSPAN_INDEX]	= { .type = NLA_U32 },
1578f551c91dSWilliam Tu 	[IFLA_GRE_ERSPAN_VER]	= { .type = NLA_U8 },
1579f551c91dSWilliam Tu 	[IFLA_GRE_ERSPAN_DIR]	= { .type = NLA_U8 },
1580f551c91dSWilliam Tu 	[IFLA_GRE_ERSPAN_HWID]	= { .type = NLA_U16 },
1581c19e654dSHerbert Xu };
1582c19e654dSHerbert Xu 
1583c19e654dSHerbert Xu static struct rtnl_link_ops ipgre_link_ops __read_mostly = {
1584c19e654dSHerbert Xu 	.kind		= "gre",
1585c19e654dSHerbert Xu 	.maxtype	= IFLA_GRE_MAX,
1586c19e654dSHerbert Xu 	.policy		= ipgre_policy,
1587c19e654dSHerbert Xu 	.priv_size	= sizeof(struct ip_tunnel),
1588c19e654dSHerbert Xu 	.setup		= ipgre_tunnel_setup,
1589c19e654dSHerbert Xu 	.validate	= ipgre_tunnel_validate,
1590c19e654dSHerbert Xu 	.newlink	= ipgre_newlink,
1591c19e654dSHerbert Xu 	.changelink	= ipgre_changelink,
1592c5441932SPravin B Shelar 	.dellink	= ip_tunnel_dellink,
1593c19e654dSHerbert Xu 	.get_size	= ipgre_get_size,
1594c19e654dSHerbert Xu 	.fill_info	= ipgre_fill_info,
15951728d4faSNicolas Dichtel 	.get_link_net	= ip_tunnel_get_link_net,
1596c19e654dSHerbert Xu };
1597c19e654dSHerbert Xu 
1598e1a80002SHerbert Xu static struct rtnl_link_ops ipgre_tap_ops __read_mostly = {
1599e1a80002SHerbert Xu 	.kind		= "gretap",
1600e1a80002SHerbert Xu 	.maxtype	= IFLA_GRE_MAX,
1601e1a80002SHerbert Xu 	.policy		= ipgre_policy,
1602e1a80002SHerbert Xu 	.priv_size	= sizeof(struct ip_tunnel),
1603e1a80002SHerbert Xu 	.setup		= ipgre_tap_setup,
1604e1a80002SHerbert Xu 	.validate	= ipgre_tap_validate,
1605e1a80002SHerbert Xu 	.newlink	= ipgre_newlink,
1606e1a80002SHerbert Xu 	.changelink	= ipgre_changelink,
1607c5441932SPravin B Shelar 	.dellink	= ip_tunnel_dellink,
1608e1a80002SHerbert Xu 	.get_size	= ipgre_get_size,
1609e1a80002SHerbert Xu 	.fill_info	= ipgre_fill_info,
16101728d4faSNicolas Dichtel 	.get_link_net	= ip_tunnel_get_link_net,
1611e1a80002SHerbert Xu };
1612e1a80002SHerbert Xu 
161384e54fe0SWilliam Tu static struct rtnl_link_ops erspan_link_ops __read_mostly = {
161484e54fe0SWilliam Tu 	.kind		= "erspan",
161584e54fe0SWilliam Tu 	.maxtype	= IFLA_GRE_MAX,
161684e54fe0SWilliam Tu 	.policy		= ipgre_policy,
161784e54fe0SWilliam Tu 	.priv_size	= sizeof(struct ip_tunnel),
161884e54fe0SWilliam Tu 	.setup		= erspan_setup,
161984e54fe0SWilliam Tu 	.validate	= erspan_validate,
1620e1f8f78fSPetr Machata 	.newlink	= erspan_newlink,
1621e1f8f78fSPetr Machata 	.changelink	= erspan_changelink,
162284e54fe0SWilliam Tu 	.dellink	= ip_tunnel_dellink,
162384e54fe0SWilliam Tu 	.get_size	= ipgre_get_size,
162484e54fe0SWilliam Tu 	.fill_info	= ipgre_fill_info,
162584e54fe0SWilliam Tu 	.get_link_net	= ip_tunnel_get_link_net,
162684e54fe0SWilliam Tu };
162784e54fe0SWilliam Tu 
1628b2acd1dcSPravin B Shelar struct net_device *gretap_fb_dev_create(struct net *net, const char *name,
1629b2acd1dcSPravin B Shelar 					u8 name_assign_type)
1630b2acd1dcSPravin B Shelar {
1631b2acd1dcSPravin B Shelar 	struct nlattr *tb[IFLA_MAX + 1];
1632b2acd1dcSPravin B Shelar 	struct net_device *dev;
1633106da663SNicolas Dichtel 	LIST_HEAD(list_kill);
1634b2acd1dcSPravin B Shelar 	struct ip_tunnel *t;
1635b2acd1dcSPravin B Shelar 	int err;
1636b2acd1dcSPravin B Shelar 
1637b2acd1dcSPravin B Shelar 	memset(&tb, 0, sizeof(tb));
1638b2acd1dcSPravin B Shelar 
1639b2acd1dcSPravin B Shelar 	dev = rtnl_create_link(net, name, name_assign_type,
1640d0522f1cSDavid Ahern 			       &ipgre_tap_ops, tb, NULL);
1641b2acd1dcSPravin B Shelar 	if (IS_ERR(dev))
1642b2acd1dcSPravin B Shelar 		return dev;
1643b2acd1dcSPravin B Shelar 
1644b2acd1dcSPravin B Shelar 	/* Configure flow based GRE device. */
1645b2acd1dcSPravin B Shelar 	t = netdev_priv(dev);
1646b2acd1dcSPravin B Shelar 	t->collect_md = true;
1647b2acd1dcSPravin B Shelar 
16487a3f4a18SMatthias Schiffer 	err = ipgre_newlink(net, dev, tb, NULL, NULL);
1649106da663SNicolas Dichtel 	if (err < 0) {
1650106da663SNicolas Dichtel 		free_netdev(dev);
1651106da663SNicolas Dichtel 		return ERR_PTR(err);
1652106da663SNicolas Dichtel 	}
16537e059158SDavid Wragg 
16547e059158SDavid Wragg 	/* openvswitch users expect packet sizes to be unrestricted,
16557e059158SDavid Wragg 	 * so set the largest MTU we can.
16567e059158SDavid Wragg 	 */
16577e059158SDavid Wragg 	err = __ip_tunnel_change_mtu(dev, IP_MAX_MTU, false);
16587e059158SDavid Wragg 	if (err)
16597e059158SDavid Wragg 		goto out;
16607e059158SDavid Wragg 
1661da6f1da8SNicolas Dichtel 	err = rtnl_configure_link(dev, NULL);
1662da6f1da8SNicolas Dichtel 	if (err < 0)
1663da6f1da8SNicolas Dichtel 		goto out;
1664da6f1da8SNicolas Dichtel 
1665b2acd1dcSPravin B Shelar 	return dev;
1666b2acd1dcSPravin B Shelar out:
1667106da663SNicolas Dichtel 	ip_tunnel_dellink(dev, &list_kill);
1668106da663SNicolas Dichtel 	unregister_netdevice_many(&list_kill);
1669b2acd1dcSPravin B Shelar 	return ERR_PTR(err);
1670b2acd1dcSPravin B Shelar }
1671b2acd1dcSPravin B Shelar EXPORT_SYMBOL_GPL(gretap_fb_dev_create);
1672b2acd1dcSPravin B Shelar 
1673c5441932SPravin B Shelar static int __net_init ipgre_tap_init_net(struct net *net)
1674c5441932SPravin B Shelar {
16752e15ea39SPravin B Shelar 	return ip_tunnel_init_net(net, gre_tap_net_id, &ipgre_tap_ops, "gretap0");
1676c5441932SPravin B Shelar }
1677c5441932SPravin B Shelar 
167864bc1781SEric Dumazet static void __net_exit ipgre_tap_exit_batch_net(struct list_head *list_net)
1679c5441932SPravin B Shelar {
168064bc1781SEric Dumazet 	ip_tunnel_delete_nets(list_net, gre_tap_net_id, &ipgre_tap_ops);
1681c5441932SPravin B Shelar }
1682c5441932SPravin B Shelar 
1683c5441932SPravin B Shelar static struct pernet_operations ipgre_tap_net_ops = {
1684c5441932SPravin B Shelar 	.init = ipgre_tap_init_net,
168564bc1781SEric Dumazet 	.exit_batch = ipgre_tap_exit_batch_net,
1686c5441932SPravin B Shelar 	.id   = &gre_tap_net_id,
1687c5441932SPravin B Shelar 	.size = sizeof(struct ip_tunnel_net),
1688c5441932SPravin B Shelar };
16891da177e4SLinus Torvalds 
169084e54fe0SWilliam Tu static int __net_init erspan_init_net(struct net *net)
169184e54fe0SWilliam Tu {
169284e54fe0SWilliam Tu 	return ip_tunnel_init_net(net, erspan_net_id,
169384e54fe0SWilliam Tu 				  &erspan_link_ops, "erspan0");
169484e54fe0SWilliam Tu }
169584e54fe0SWilliam Tu 
169664bc1781SEric Dumazet static void __net_exit erspan_exit_batch_net(struct list_head *net_list)
169784e54fe0SWilliam Tu {
169864bc1781SEric Dumazet 	ip_tunnel_delete_nets(net_list, erspan_net_id, &erspan_link_ops);
169984e54fe0SWilliam Tu }
170084e54fe0SWilliam Tu 
170184e54fe0SWilliam Tu static struct pernet_operations erspan_net_ops = {
170284e54fe0SWilliam Tu 	.init = erspan_init_net,
170364bc1781SEric Dumazet 	.exit_batch = erspan_exit_batch_net,
170484e54fe0SWilliam Tu 	.id   = &erspan_net_id,
170584e54fe0SWilliam Tu 	.size = sizeof(struct ip_tunnel_net),
170684e54fe0SWilliam Tu };
170784e54fe0SWilliam Tu 
17081da177e4SLinus Torvalds static int __init ipgre_init(void)
17091da177e4SLinus Torvalds {
17101da177e4SLinus Torvalds 	int err;
17111da177e4SLinus Torvalds 
1712058bd4d2SJoe Perches 	pr_info("GRE over IPv4 tunneling driver\n");
17131da177e4SLinus Torvalds 
1714cfb8fbf2SEric W. Biederman 	err = register_pernet_device(&ipgre_net_ops);
171559a4c759SPavel Emelyanov 	if (err < 0)
1716c2892f02SAlexey Dobriyan 		return err;
1717c2892f02SAlexey Dobriyan 
1718c5441932SPravin B Shelar 	err = register_pernet_device(&ipgre_tap_net_ops);
1719c5441932SPravin B Shelar 	if (err < 0)
1720e3d0328cSWilliam Tu 		goto pnet_tap_failed;
1721c5441932SPravin B Shelar 
172284e54fe0SWilliam Tu 	err = register_pernet_device(&erspan_net_ops);
172384e54fe0SWilliam Tu 	if (err < 0)
172484e54fe0SWilliam Tu 		goto pnet_erspan_failed;
172584e54fe0SWilliam Tu 
17269f57c67cSPravin B Shelar 	err = gre_add_protocol(&ipgre_protocol, GREPROTO_CISCO);
1727c2892f02SAlexey Dobriyan 	if (err < 0) {
1728058bd4d2SJoe Perches 		pr_info("%s: can't add protocol\n", __func__);
1729c2892f02SAlexey Dobriyan 		goto add_proto_failed;
1730c2892f02SAlexey Dobriyan 	}
17317daa0004SPavel Emelyanov 
1732c19e654dSHerbert Xu 	err = rtnl_link_register(&ipgre_link_ops);
1733c19e654dSHerbert Xu 	if (err < 0)
1734c19e654dSHerbert Xu 		goto rtnl_link_failed;
1735c19e654dSHerbert Xu 
1736e1a80002SHerbert Xu 	err = rtnl_link_register(&ipgre_tap_ops);
1737e1a80002SHerbert Xu 	if (err < 0)
1738e1a80002SHerbert Xu 		goto tap_ops_failed;
1739e1a80002SHerbert Xu 
174084e54fe0SWilliam Tu 	err = rtnl_link_register(&erspan_link_ops);
174184e54fe0SWilliam Tu 	if (err < 0)
174284e54fe0SWilliam Tu 		goto erspan_link_failed;
174384e54fe0SWilliam Tu 
1744c5441932SPravin B Shelar 	return 0;
1745c19e654dSHerbert Xu 
174684e54fe0SWilliam Tu erspan_link_failed:
174784e54fe0SWilliam Tu 	rtnl_link_unregister(&ipgre_tap_ops);
1748e1a80002SHerbert Xu tap_ops_failed:
1749e1a80002SHerbert Xu 	rtnl_link_unregister(&ipgre_link_ops);
1750c19e654dSHerbert Xu rtnl_link_failed:
17519f57c67cSPravin B Shelar 	gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO);
1752c2892f02SAlexey Dobriyan add_proto_failed:
175384e54fe0SWilliam Tu 	unregister_pernet_device(&erspan_net_ops);
175484e54fe0SWilliam Tu pnet_erspan_failed:
1755c5441932SPravin B Shelar 	unregister_pernet_device(&ipgre_tap_net_ops);
1756e3d0328cSWilliam Tu pnet_tap_failed:
1757c2892f02SAlexey Dobriyan 	unregister_pernet_device(&ipgre_net_ops);
1758c5441932SPravin B Shelar 	return err;
17591da177e4SLinus Torvalds }
17601da177e4SLinus Torvalds 
1761db44575fSAlexey Kuznetsov static void __exit ipgre_fini(void)
17621da177e4SLinus Torvalds {
1763e1a80002SHerbert Xu 	rtnl_link_unregister(&ipgre_tap_ops);
1764c19e654dSHerbert Xu 	rtnl_link_unregister(&ipgre_link_ops);
176584e54fe0SWilliam Tu 	rtnl_link_unregister(&erspan_link_ops);
17669f57c67cSPravin B Shelar 	gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO);
1767c5441932SPravin B Shelar 	unregister_pernet_device(&ipgre_tap_net_ops);
1768c2892f02SAlexey Dobriyan 	unregister_pernet_device(&ipgre_net_ops);
176984e54fe0SWilliam Tu 	unregister_pernet_device(&erspan_net_ops);
17701da177e4SLinus Torvalds }
17711da177e4SLinus Torvalds 
17721da177e4SLinus Torvalds module_init(ipgre_init);
17731da177e4SLinus Torvalds module_exit(ipgre_fini);
17741da177e4SLinus Torvalds MODULE_LICENSE("GPL");
17754d74f8baSPatrick McHardy MODULE_ALIAS_RTNL_LINK("gre");
17764d74f8baSPatrick McHardy MODULE_ALIAS_RTNL_LINK("gretap");
177784e54fe0SWilliam Tu MODULE_ALIAS_RTNL_LINK("erspan");
17788909c9adSVasiliy Kulikov MODULE_ALIAS_NETDEV("gre0");
1779c5441932SPravin B Shelar MODULE_ALIAS_NETDEV("gretap0");
178084e54fe0SWilliam Tu MODULE_ALIAS_NETDEV("erspan0");
1781