xref: /linux/net/ipv4/ip_gre.c (revision 2874c5fd284268364ece81a7bd936f3c8168e567)
1*2874c5fdSThomas 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 
25184e54fe0SWilliam Tu static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi,
25284e54fe0SWilliam Tu 		      int gre_hdr_len)
25384e54fe0SWilliam Tu {
25484e54fe0SWilliam Tu 	struct net *net = dev_net(skb->dev);
25584e54fe0SWilliam Tu 	struct metadata_dst *tun_dst = NULL;
2561d7e2ed2SWilliam Tu 	struct erspan_base_hdr *ershdr;
25784e54fe0SWilliam Tu 	struct ip_tunnel_net *itn;
25884e54fe0SWilliam Tu 	struct ip_tunnel *tunnel;
25984e54fe0SWilliam Tu 	const struct iphdr *iph;
2603df19283SWilliam Tu 	struct erspan_md2 *md2;
2611d7e2ed2SWilliam Tu 	int ver;
26284e54fe0SWilliam Tu 	int len;
26384e54fe0SWilliam Tu 
26484e54fe0SWilliam Tu 	itn = net_generic(net, erspan_net_id);
26584e54fe0SWilliam Tu 
26684e54fe0SWilliam Tu 	iph = ip_hdr(skb);
2671d7e2ed2SWilliam Tu 	ershdr = (struct erspan_base_hdr *)(skb->data + gre_hdr_len);
268c69de58bSWilliam Tu 	ver = ershdr->ver;
26984e54fe0SWilliam Tu 
27084e54fe0SWilliam Tu 	tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex,
27184e54fe0SWilliam Tu 				  tpi->flags | TUNNEL_KEY,
27284e54fe0SWilliam Tu 				  iph->saddr, iph->daddr, tpi->key);
27384e54fe0SWilliam Tu 
27484e54fe0SWilliam Tu 	if (tunnel) {
2751d7e2ed2SWilliam Tu 		len = gre_hdr_len + erspan_hdr_len(ver);
2761d7e2ed2SWilliam Tu 		if (unlikely(!pskb_may_pull(skb, len)))
277ae3e1337SWilliam Tu 			return PACKET_REJECT;
2781d7e2ed2SWilliam Tu 
27984e54fe0SWilliam Tu 		if (__iptunnel_pull_header(skb,
2801d7e2ed2SWilliam Tu 					   len,
28184e54fe0SWilliam Tu 					   htons(ETH_P_TEB),
28284e54fe0SWilliam Tu 					   false, false) < 0)
28384e54fe0SWilliam Tu 			goto drop;
28484e54fe0SWilliam Tu 
2851a66a836SWilliam Tu 		if (tunnel->collect_md) {
286492b67e2SLorenzo Bianconi 			struct erspan_metadata *pkt_md, *md;
2871a66a836SWilliam Tu 			struct ip_tunnel_info *info;
288492b67e2SLorenzo Bianconi 			unsigned char *gh;
2891a66a836SWilliam Tu 			__be64 tun_id;
2901a66a836SWilliam Tu 			__be16 flags;
2911a66a836SWilliam Tu 
2921a66a836SWilliam Tu 			tpi->flags |= TUNNEL_KEY;
2931a66a836SWilliam Tu 			flags = tpi->flags;
2941a66a836SWilliam Tu 			tun_id = key32_to_tunnel_id(tpi->key);
2951a66a836SWilliam Tu 
2961a66a836SWilliam Tu 			tun_dst = ip_tun_rx_dst(skb, flags,
2971a66a836SWilliam Tu 						tun_id, sizeof(*md));
2981a66a836SWilliam Tu 			if (!tun_dst)
2991a66a836SWilliam Tu 				return PACKET_REJECT;
3001a66a836SWilliam Tu 
301492b67e2SLorenzo Bianconi 			/* skb can be uncloned in __iptunnel_pull_header, so
302492b67e2SLorenzo Bianconi 			 * old pkt_md is no longer valid and we need to reset
303492b67e2SLorenzo Bianconi 			 * it
304492b67e2SLorenzo Bianconi 			 */
305492b67e2SLorenzo Bianconi 			gh = skb_network_header(skb) +
306492b67e2SLorenzo Bianconi 			     skb_network_header_len(skb);
307492b67e2SLorenzo Bianconi 			pkt_md = (struct erspan_metadata *)(gh + gre_hdr_len +
308492b67e2SLorenzo Bianconi 							    sizeof(*ershdr));
3091a66a836SWilliam Tu 			md = ip_tunnel_info_opts(&tun_dst->u.tun_info);
310f551c91dSWilliam Tu 			md->version = ver;
3113df19283SWilliam Tu 			md2 = &md->u.md2;
3123df19283SWilliam Tu 			memcpy(md2, pkt_md, ver == 1 ? ERSPAN_V1_MDSIZE :
3133df19283SWilliam Tu 						       ERSPAN_V2_MDSIZE);
314f551c91dSWilliam Tu 
3151a66a836SWilliam Tu 			info = &tun_dst->u.tun_info;
3161a66a836SWilliam Tu 			info->key.tun_flags |= TUNNEL_ERSPAN_OPT;
3171a66a836SWilliam Tu 			info->options_len = sizeof(*md);
3181a66a836SWilliam Tu 		}
3191a66a836SWilliam Tu 
32084e54fe0SWilliam Tu 		skb_reset_mac_header(skb);
32184e54fe0SWilliam Tu 		ip_tunnel_rcv(tunnel, skb, tpi, tun_dst, log_ecn_error);
32284e54fe0SWilliam Tu 		return PACKET_RCVD;
32384e54fe0SWilliam Tu 	}
3245a64506bSHaishuang Yan 	return PACKET_REJECT;
3255a64506bSHaishuang Yan 
32684e54fe0SWilliam Tu drop:
32784e54fe0SWilliam Tu 	kfree_skb(skb);
32884e54fe0SWilliam Tu 	return PACKET_RCVD;
32984e54fe0SWilliam Tu }
33084e54fe0SWilliam Tu 
331125372faSJiri Benc static int __ipgre_rcv(struct sk_buff *skb, const struct tnl_ptk_info *tpi,
332125372faSJiri Benc 		       struct ip_tunnel_net *itn, int hdr_len, bool raw_proto)
3331da177e4SLinus Torvalds {
3342e15ea39SPravin B Shelar 	struct metadata_dst *tun_dst = NULL;
335b71d1d42SEric Dumazet 	const struct iphdr *iph;
3361da177e4SLinus Torvalds 	struct ip_tunnel *tunnel;
3371da177e4SLinus Torvalds 
338eddc9ec5SArnaldo Carvalho de Melo 	iph = ip_hdr(skb);
339bda7bb46SPravin B Shelar 	tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, tpi->flags,
340bda7bb46SPravin B Shelar 				  iph->saddr, iph->daddr, tpi->key);
3411da177e4SLinus Torvalds 
342d2083287Sstephen hemminger 	if (tunnel) {
343125372faSJiri Benc 		if (__iptunnel_pull_header(skb, hdr_len, tpi->proto,
344125372faSJiri Benc 					   raw_proto, false) < 0)
345244a797bSJiri Benc 			goto drop;
346244a797bSJiri Benc 
347e271c7b4SJiri Benc 		if (tunnel->dev->type != ARPHRD_NONE)
3480e3da5bbSTimo Teräs 			skb_pop_mac_header(skb);
349e271c7b4SJiri Benc 		else
350e271c7b4SJiri Benc 			skb_reset_mac_header(skb);
3512e15ea39SPravin B Shelar 		if (tunnel->collect_md) {
352c29a70d2SPravin B Shelar 			__be16 flags;
353c29a70d2SPravin B Shelar 			__be64 tun_id;
3542e15ea39SPravin B Shelar 
355c29a70d2SPravin B Shelar 			flags = tpi->flags & (TUNNEL_CSUM | TUNNEL_KEY);
356d817f432SAmir Vadai 			tun_id = key32_to_tunnel_id(tpi->key);
357c29a70d2SPravin B Shelar 			tun_dst = ip_tun_rx_dst(skb, flags, tun_id, 0);
3582e15ea39SPravin B Shelar 			if (!tun_dst)
3592e15ea39SPravin B Shelar 				return PACKET_REJECT;
3602e15ea39SPravin B Shelar 		}
3612e15ea39SPravin B Shelar 
3622e15ea39SPravin B Shelar 		ip_tunnel_rcv(tunnel, skb, tpi, tun_dst, log_ecn_error);
363bda7bb46SPravin B Shelar 		return PACKET_RCVD;
3641da177e4SLinus Torvalds 	}
365125372faSJiri Benc 	return PACKET_NEXT;
366244a797bSJiri Benc 
367244a797bSJiri Benc drop:
368244a797bSJiri Benc 	kfree_skb(skb);
369244a797bSJiri Benc 	return PACKET_RCVD;
3701da177e4SLinus Torvalds }
3711da177e4SLinus Torvalds 
372125372faSJiri Benc static int ipgre_rcv(struct sk_buff *skb, const struct tnl_ptk_info *tpi,
373125372faSJiri Benc 		     int hdr_len)
374125372faSJiri Benc {
375125372faSJiri Benc 	struct net *net = dev_net(skb->dev);
376125372faSJiri Benc 	struct ip_tunnel_net *itn;
377125372faSJiri Benc 	int res;
378125372faSJiri Benc 
379125372faSJiri Benc 	if (tpi->proto == htons(ETH_P_TEB))
380125372faSJiri Benc 		itn = net_generic(net, gre_tap_net_id);
381125372faSJiri Benc 	else
382125372faSJiri Benc 		itn = net_generic(net, ipgre_net_id);
383125372faSJiri Benc 
384125372faSJiri Benc 	res = __ipgre_rcv(skb, tpi, itn, hdr_len, false);
385125372faSJiri Benc 	if (res == PACKET_NEXT && tpi->proto == htons(ETH_P_TEB)) {
386125372faSJiri Benc 		/* ipgre tunnels in collect metadata mode should receive
387125372faSJiri Benc 		 * also ETH_P_TEB traffic.
388125372faSJiri Benc 		 */
389125372faSJiri Benc 		itn = net_generic(net, ipgre_net_id);
390125372faSJiri Benc 		res = __ipgre_rcv(skb, tpi, itn, hdr_len, true);
391125372faSJiri Benc 	}
392125372faSJiri Benc 	return res;
393125372faSJiri Benc }
394125372faSJiri Benc 
3959f57c67cSPravin B Shelar static int gre_rcv(struct sk_buff *skb)
3969f57c67cSPravin B Shelar {
3979f57c67cSPravin B Shelar 	struct tnl_ptk_info tpi;
3989f57c67cSPravin B Shelar 	bool csum_err = false;
39995f5c64cSTom Herbert 	int hdr_len;
4009f57c67cSPravin B Shelar 
4019f57c67cSPravin B Shelar #ifdef CONFIG_NET_IPGRE_BROADCAST
4029f57c67cSPravin B Shelar 	if (ipv4_is_multicast(ip_hdr(skb)->daddr)) {
4039f57c67cSPravin B Shelar 		/* Looped back packet, drop it! */
4049f57c67cSPravin B Shelar 		if (rt_is_output_route(skb_rtable(skb)))
4059f57c67cSPravin B Shelar 			goto drop;
4069f57c67cSPravin B Shelar 	}
4079f57c67cSPravin B Shelar #endif
4089f57c67cSPravin B Shelar 
409e582615aSEric Dumazet 	hdr_len = gre_parse_header(skb, &tpi, &csum_err, htons(ETH_P_IP), 0);
410f132ae7cSJiri Benc 	if (hdr_len < 0)
41195f5c64cSTom Herbert 		goto drop;
41295f5c64cSTom Herbert 
413f551c91dSWilliam Tu 	if (unlikely(tpi.proto == htons(ETH_P_ERSPAN) ||
414f551c91dSWilliam Tu 		     tpi.proto == htons(ETH_P_ERSPAN2))) {
41584e54fe0SWilliam Tu 		if (erspan_rcv(skb, &tpi, hdr_len) == PACKET_RCVD)
41684e54fe0SWilliam Tu 			return 0;
417dd8d5b8cSHaishuang Yan 		goto out;
41884e54fe0SWilliam Tu 	}
41984e54fe0SWilliam Tu 
420244a797bSJiri Benc 	if (ipgre_rcv(skb, &tpi, hdr_len) == PACKET_RCVD)
4219f57c67cSPravin B Shelar 		return 0;
4229f57c67cSPravin B Shelar 
423dd8d5b8cSHaishuang Yan out:
4249f57c67cSPravin B Shelar 	icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
4259f57c67cSPravin B Shelar drop:
4269f57c67cSPravin B Shelar 	kfree_skb(skb);
4279f57c67cSPravin B Shelar 	return 0;
4289f57c67cSPravin B Shelar }
4299f57c67cSPravin B Shelar 
430c5441932SPravin B Shelar static void __gre_xmit(struct sk_buff *skb, struct net_device *dev,
431c5441932SPravin B Shelar 		       const struct iphdr *tnl_params,
432c5441932SPravin B Shelar 		       __be16 proto)
433c5441932SPravin B Shelar {
434c5441932SPravin B Shelar 	struct ip_tunnel *tunnel = netdev_priv(dev);
435c5441932SPravin B Shelar 
436c5441932SPravin B Shelar 	if (tunnel->parms.o_flags & TUNNEL_SEQ)
437c5441932SPravin B Shelar 		tunnel->o_seqno++;
438cef401deSEric Dumazet 
439c5441932SPravin B Shelar 	/* Push GRE header. */
440182a352dSTom Herbert 	gre_build_header(skb, tunnel->tun_hlen,
441182a352dSTom Herbert 			 tunnel->parms.o_flags, proto, tunnel->parms.o_key,
442182a352dSTom Herbert 			 htonl(tunnel->o_seqno));
4431da177e4SLinus Torvalds 
444bf3d6a8fSNicolas Dichtel 	ip_tunnel_xmit(skb, dev, tnl_params, tnl_params->protocol);
4451da177e4SLinus Torvalds }
4461da177e4SLinus Torvalds 
447aed069dfSAlexander Duyck static int gre_handle_offloads(struct sk_buff *skb, bool csum)
448b2acd1dcSPravin B Shelar {
4496fa79666SEdward Cree 	return iptunnel_handle_offloads(skb, csum ? SKB_GSO_GRE_CSUM : SKB_GSO_GRE);
450b2acd1dcSPravin B Shelar }
451b2acd1dcSPravin B Shelar 
452862a03c3SWilliam Tu static void gre_fb_xmit(struct sk_buff *skb, struct net_device *dev,
453862a03c3SWilliam Tu 			__be16 proto)
454862a03c3SWilliam Tu {
45577a5196aSWilliam Tu 	struct ip_tunnel *tunnel = netdev_priv(dev);
456862a03c3SWilliam Tu 	struct ip_tunnel_info *tun_info;
457862a03c3SWilliam Tu 	const struct ip_tunnel_key *key;
458862a03c3SWilliam Tu 	int tunnel_hlen;
459962924faSwenxu 	__be16 flags;
460862a03c3SWilliam Tu 
461862a03c3SWilliam Tu 	tun_info = skb_tunnel_info(skb);
462862a03c3SWilliam Tu 	if (unlikely(!tun_info || !(tun_info->mode & IP_TUNNEL_INFO_TX) ||
463862a03c3SWilliam Tu 		     ip_tunnel_info_af(tun_info) != AF_INET))
464862a03c3SWilliam Tu 		goto err_free_skb;
465862a03c3SWilliam Tu 
466862a03c3SWilliam Tu 	key = &tun_info->key;
467862a03c3SWilliam Tu 	tunnel_hlen = gre_calc_hlen(key->tun_flags);
468862a03c3SWilliam Tu 
469962924faSwenxu 	if (skb_cow_head(skb, dev->needed_headroom))
470962924faSwenxu 		goto err_free_skb;
4712e15ea39SPravin B Shelar 
4722e15ea39SPravin B Shelar 	/* Push Tunnel header. */
473aed069dfSAlexander Duyck 	if (gre_handle_offloads(skb, !!(tun_info->key.tun_flags & TUNNEL_CSUM)))
474962924faSwenxu 		goto err_free_skb;
4752e15ea39SPravin B Shelar 
47677a5196aSWilliam Tu 	flags = tun_info->key.tun_flags &
47777a5196aSWilliam Tu 		(TUNNEL_CSUM | TUNNEL_KEY | TUNNEL_SEQ);
478cba65321SDavid S. Miller 	gre_build_header(skb, tunnel_hlen, flags, proto,
47977a5196aSWilliam Tu 			 tunnel_id_to_key32(tun_info->key.tun_id),
48015746394SColin Ian King 			 (flags & TUNNEL_SEQ) ? htonl(tunnel->o_seqno++) : 0);
4812e15ea39SPravin B Shelar 
482962924faSwenxu 	ip_md_tunnel_xmit(skb, dev, IPPROTO_GRE, tunnel_hlen);
483039f5062SPravin B Shelar 
4842e15ea39SPravin B Shelar 	return;
4852e15ea39SPravin B Shelar 
4862e15ea39SPravin B Shelar err_free_skb:
4872e15ea39SPravin B Shelar 	kfree_skb(skb);
4882e15ea39SPravin B Shelar 	dev->stats.tx_dropped++;
4892e15ea39SPravin B Shelar }
4902e15ea39SPravin B Shelar 
49120704bd1SXin Long static void erspan_fb_xmit(struct sk_buff *skb, struct net_device *dev)
4921a66a836SWilliam Tu {
4931a66a836SWilliam Tu 	struct ip_tunnel *tunnel = netdev_priv(dev);
4941a66a836SWilliam Tu 	struct ip_tunnel_info *tun_info;
4951a66a836SWilliam Tu 	const struct ip_tunnel_key *key;
4961a66a836SWilliam Tu 	struct erspan_metadata *md;
4971a66a836SWilliam Tu 	bool truncate = false;
498962924faSwenxu 	__be16 proto;
4991a66a836SWilliam Tu 	int tunnel_hlen;
500f551c91dSWilliam Tu 	int version;
5011baf5ebfSWilliam Tu 	int nhoff;
502d5db21a3SWilliam Tu 	int thoff;
5031a66a836SWilliam Tu 
5041a66a836SWilliam Tu 	tun_info = skb_tunnel_info(skb);
5051a66a836SWilliam Tu 	if (unlikely(!tun_info || !(tun_info->mode & IP_TUNNEL_INFO_TX) ||
5061a66a836SWilliam Tu 		     ip_tunnel_info_af(tun_info) != AF_INET))
5071a66a836SWilliam Tu 		goto err_free_skb;
5081a66a836SWilliam Tu 
5091a66a836SWilliam Tu 	key = &tun_info->key;
510256c87c1SPieter Jansen van Vuuren 	if (!(tun_info->key.tun_flags & TUNNEL_ERSPAN_OPT))
511962924faSwenxu 		goto err_free_skb;
512f551c91dSWilliam Tu 	md = ip_tunnel_info_opts(tun_info);
513f551c91dSWilliam Tu 	if (!md)
514962924faSwenxu 		goto err_free_skb;
5151a66a836SWilliam Tu 
5161a66a836SWilliam Tu 	/* ERSPAN has fixed 8 byte GRE header */
517f551c91dSWilliam Tu 	version = md->version;
518f551c91dSWilliam Tu 	tunnel_hlen = 8 + erspan_hdr_len(version);
5191a66a836SWilliam Tu 
520962924faSwenxu 	if (skb_cow_head(skb, dev->needed_headroom))
521962924faSwenxu 		goto err_free_skb;
5221a66a836SWilliam Tu 
5231a66a836SWilliam Tu 	if (gre_handle_offloads(skb, false))
524962924faSwenxu 		goto err_free_skb;
5251a66a836SWilliam Tu 
526f192970dSWilliam Tu 	if (skb->len > dev->mtu + dev->hard_header_len) {
527f192970dSWilliam Tu 		pskb_trim(skb, dev->mtu + dev->hard_header_len);
5281a66a836SWilliam Tu 		truncate = true;
5291a66a836SWilliam Tu 	}
5301a66a836SWilliam Tu 
5311baf5ebfSWilliam Tu 	nhoff = skb_network_header(skb) - skb_mac_header(skb);
5321baf5ebfSWilliam Tu 	if (skb->protocol == htons(ETH_P_IP) &&
5331baf5ebfSWilliam Tu 	    (ntohs(ip_hdr(skb)->tot_len) > skb->len - nhoff))
5341baf5ebfSWilliam Tu 		truncate = true;
5351baf5ebfSWilliam Tu 
536d5db21a3SWilliam Tu 	thoff = skb_transport_header(skb) - skb_mac_header(skb);
537d5db21a3SWilliam Tu 	if (skb->protocol == htons(ETH_P_IPV6) &&
538d5db21a3SWilliam Tu 	    (ntohs(ipv6_hdr(skb)->payload_len) > skb->len - thoff))
539d5db21a3SWilliam Tu 		truncate = true;
540d5db21a3SWilliam Tu 
541f551c91dSWilliam Tu 	if (version == 1) {
542c69de58bSWilliam Tu 		erspan_build_header(skb, ntohl(tunnel_id_to_key32(key->tun_id)),
5431d7e2ed2SWilliam Tu 				    ntohl(md->u.index), truncate, true);
54420704bd1SXin Long 		proto = htons(ETH_P_ERSPAN);
545f551c91dSWilliam Tu 	} else if (version == 2) {
546c69de58bSWilliam Tu 		erspan_build_header_v2(skb,
547c69de58bSWilliam Tu 				       ntohl(tunnel_id_to_key32(key->tun_id)),
548c69de58bSWilliam Tu 				       md->u.md2.dir,
549c69de58bSWilliam Tu 				       get_hwid(&md->u.md2),
550c69de58bSWilliam Tu 				       truncate, true);
55120704bd1SXin Long 		proto = htons(ETH_P_ERSPAN2);
552f551c91dSWilliam Tu 	} else {
553962924faSwenxu 		goto err_free_skb;
554f551c91dSWilliam Tu 	}
5551a66a836SWilliam Tu 
5561a66a836SWilliam Tu 	gre_build_header(skb, 8, TUNNEL_SEQ,
55720704bd1SXin Long 			 proto, 0, htonl(tunnel->o_seqno++));
5581a66a836SWilliam Tu 
559962924faSwenxu 	ip_md_tunnel_xmit(skb, dev, IPPROTO_GRE, tunnel_hlen);
5601a66a836SWilliam Tu 
5611a66a836SWilliam Tu 	return;
5621a66a836SWilliam Tu 
5631a66a836SWilliam Tu err_free_skb:
5641a66a836SWilliam Tu 	kfree_skb(skb);
5651a66a836SWilliam Tu 	dev->stats.tx_dropped++;
5661a66a836SWilliam Tu }
5671a66a836SWilliam Tu 
568fc4099f1SPravin B Shelar static int gre_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
569fc4099f1SPravin B Shelar {
570fc4099f1SPravin B Shelar 	struct ip_tunnel_info *info = skb_tunnel_info(skb);
571962924faSwenxu 	const struct ip_tunnel_key *key;
572fc4099f1SPravin B Shelar 	struct rtable *rt;
573fc4099f1SPravin B Shelar 	struct flowi4 fl4;
574fc4099f1SPravin B Shelar 
575fc4099f1SPravin B Shelar 	if (ip_tunnel_info_af(info) != AF_INET)
576fc4099f1SPravin B Shelar 		return -EINVAL;
577fc4099f1SPravin B Shelar 
578962924faSwenxu 	key = &info->key;
579962924faSwenxu 	ip_tunnel_init_flow(&fl4, IPPROTO_GRE, key->u.ipv4.dst, key->u.ipv4.src,
580962924faSwenxu 			    tunnel_id_to_key32(key->tun_id), key->tos, 0,
58124ba1440Swenxu 			    skb->mark, skb_get_hash(skb));
582962924faSwenxu 	rt = ip_route_output_key(dev_net(dev), &fl4);
583fc4099f1SPravin B Shelar 	if (IS_ERR(rt))
584fc4099f1SPravin B Shelar 		return PTR_ERR(rt);
585fc4099f1SPravin B Shelar 
586fc4099f1SPravin B Shelar 	ip_rt_put(rt);
587fc4099f1SPravin B Shelar 	info->key.u.ipv4.src = fl4.saddr;
588fc4099f1SPravin B Shelar 	return 0;
589fc4099f1SPravin B Shelar }
590fc4099f1SPravin B Shelar 
591c5441932SPravin B Shelar static netdev_tx_t ipgre_xmit(struct sk_buff *skb,
592c5441932SPravin B Shelar 			      struct net_device *dev)
593ee34c1ebSMichal Schmidt {
594c5441932SPravin B Shelar 	struct ip_tunnel *tunnel = netdev_priv(dev);
595c5441932SPravin B Shelar 	const struct iphdr *tnl_params;
596ee34c1ebSMichal Schmidt 
597cb9f1b78SWillem de Bruijn 	if (!pskb_inet_may_pull(skb))
598cb9f1b78SWillem de Bruijn 		goto free_skb;
599cb9f1b78SWillem de Bruijn 
6002e15ea39SPravin B Shelar 	if (tunnel->collect_md) {
6012090714eSJiri Benc 		gre_fb_xmit(skb, dev, skb->protocol);
6022e15ea39SPravin B Shelar 		return NETDEV_TX_OK;
6032e15ea39SPravin B Shelar 	}
6042e15ea39SPravin B Shelar 
605c5441932SPravin B Shelar 	if (dev->header_ops) {
606c5441932SPravin B Shelar 		/* Need space for new headers */
607c5441932SPravin B Shelar 		if (skb_cow_head(skb, dev->needed_headroom -
6082bac7cb3SChen Gang 				      (tunnel->hlen + sizeof(struct iphdr))))
609c5441932SPravin B Shelar 			goto free_skb;
610ee34c1ebSMichal Schmidt 
611c5441932SPravin B Shelar 		tnl_params = (const struct iphdr *)skb->data;
612cbb1e85fSDavid S. Miller 
613c5441932SPravin B Shelar 		/* Pull skb since ip_tunnel_xmit() needs skb->data pointing
614c5441932SPravin B Shelar 		 * to gre header.
615c5441932SPravin B Shelar 		 */
616c5441932SPravin B Shelar 		skb_pull(skb, tunnel->hlen + sizeof(struct iphdr));
6178a0033a9STimo Teräs 		skb_reset_mac_header(skb);
618c5441932SPravin B Shelar 	} else {
619c5441932SPravin B Shelar 		if (skb_cow_head(skb, dev->needed_headroom))
620c5441932SPravin B Shelar 			goto free_skb;
621c5441932SPravin B Shelar 
622c5441932SPravin B Shelar 		tnl_params = &tunnel->parms.iph;
623ee34c1ebSMichal Schmidt 	}
624e1a80002SHerbert Xu 
625aed069dfSAlexander Duyck 	if (gre_handle_offloads(skb, !!(tunnel->parms.o_flags & TUNNEL_CSUM)))
626aed069dfSAlexander Duyck 		goto free_skb;
6278a0033a9STimo Teräs 
628c5441932SPravin B Shelar 	__gre_xmit(skb, dev, tnl_params, skb->protocol);
629c5441932SPravin B Shelar 	return NETDEV_TX_OK;
630c5441932SPravin B Shelar 
631c5441932SPravin B Shelar free_skb:
6323acfa1e7SEric Dumazet 	kfree_skb(skb);
633c5441932SPravin B Shelar 	dev->stats.tx_dropped++;
634c5441932SPravin B Shelar 	return NETDEV_TX_OK;
635ee34c1ebSMichal Schmidt }
636ee34c1ebSMichal Schmidt 
63784e54fe0SWilliam Tu static netdev_tx_t erspan_xmit(struct sk_buff *skb,
63884e54fe0SWilliam Tu 			       struct net_device *dev)
63984e54fe0SWilliam Tu {
64084e54fe0SWilliam Tu 	struct ip_tunnel *tunnel = netdev_priv(dev);
64184e54fe0SWilliam Tu 	bool truncate = false;
64220704bd1SXin Long 	__be16 proto;
64384e54fe0SWilliam Tu 
644cb9f1b78SWillem de Bruijn 	if (!pskb_inet_may_pull(skb))
645cb9f1b78SWillem de Bruijn 		goto free_skb;
646cb9f1b78SWillem de Bruijn 
6471a66a836SWilliam Tu 	if (tunnel->collect_md) {
64820704bd1SXin Long 		erspan_fb_xmit(skb, dev);
6491a66a836SWilliam Tu 		return NETDEV_TX_OK;
6501a66a836SWilliam Tu 	}
6511a66a836SWilliam Tu 
65284e54fe0SWilliam Tu 	if (gre_handle_offloads(skb, false))
65384e54fe0SWilliam Tu 		goto free_skb;
65484e54fe0SWilliam Tu 
65584e54fe0SWilliam Tu 	if (skb_cow_head(skb, dev->needed_headroom))
65684e54fe0SWilliam Tu 		goto free_skb;
65784e54fe0SWilliam Tu 
658f192970dSWilliam Tu 	if (skb->len > dev->mtu + dev->hard_header_len) {
659f192970dSWilliam Tu 		pskb_trim(skb, dev->mtu + dev->hard_header_len);
66084e54fe0SWilliam Tu 		truncate = true;
66184e54fe0SWilliam Tu 	}
66284e54fe0SWilliam Tu 
66384e54fe0SWilliam Tu 	/* Push ERSPAN header */
66420704bd1SXin Long 	if (tunnel->erspan_ver == 1) {
665c69de58bSWilliam Tu 		erspan_build_header(skb, ntohl(tunnel->parms.o_key),
666c69de58bSWilliam Tu 				    tunnel->index,
667a3222dc9SWilliam Tu 				    truncate, true);
66820704bd1SXin Long 		proto = htons(ETH_P_ERSPAN);
66920704bd1SXin Long 	} else if (tunnel->erspan_ver == 2) {
670c69de58bSWilliam Tu 		erspan_build_header_v2(skb, ntohl(tunnel->parms.o_key),
671f551c91dSWilliam Tu 				       tunnel->dir, tunnel->hwid,
672f551c91dSWilliam Tu 				       truncate, true);
67320704bd1SXin Long 		proto = htons(ETH_P_ERSPAN2);
67420704bd1SXin Long 	} else {
67502f99df1SWilliam Tu 		goto free_skb;
67620704bd1SXin Long 	}
677f551c91dSWilliam Tu 
67884e54fe0SWilliam Tu 	tunnel->parms.o_flags &= ~TUNNEL_KEY;
67920704bd1SXin Long 	__gre_xmit(skb, dev, &tunnel->parms.iph, proto);
68084e54fe0SWilliam Tu 	return NETDEV_TX_OK;
68184e54fe0SWilliam Tu 
68284e54fe0SWilliam Tu free_skb:
68384e54fe0SWilliam Tu 	kfree_skb(skb);
68484e54fe0SWilliam Tu 	dev->stats.tx_dropped++;
68584e54fe0SWilliam Tu 	return NETDEV_TX_OK;
68684e54fe0SWilliam Tu }
68784e54fe0SWilliam Tu 
688c5441932SPravin B Shelar static netdev_tx_t gre_tap_xmit(struct sk_buff *skb,
689c5441932SPravin B Shelar 				struct net_device *dev)
690c5441932SPravin B Shelar {
691c5441932SPravin B Shelar 	struct ip_tunnel *tunnel = netdev_priv(dev);
692ee34c1ebSMichal Schmidt 
693cb9f1b78SWillem de Bruijn 	if (!pskb_inet_may_pull(skb))
694cb9f1b78SWillem de Bruijn 		goto free_skb;
695cb9f1b78SWillem de Bruijn 
6962e15ea39SPravin B Shelar 	if (tunnel->collect_md) {
6972090714eSJiri Benc 		gre_fb_xmit(skb, dev, htons(ETH_P_TEB));
6982e15ea39SPravin B Shelar 		return NETDEV_TX_OK;
6992e15ea39SPravin B Shelar 	}
7002e15ea39SPravin B Shelar 
701aed069dfSAlexander Duyck 	if (gre_handle_offloads(skb, !!(tunnel->parms.o_flags & TUNNEL_CSUM)))
702aed069dfSAlexander Duyck 		goto free_skb;
703ee34c1ebSMichal Schmidt 
704c5441932SPravin B Shelar 	if (skb_cow_head(skb, dev->needed_headroom))
705c5441932SPravin B Shelar 		goto free_skb;
70642aa9162SHerbert Xu 
707c5441932SPravin B Shelar 	__gre_xmit(skb, dev, &tunnel->parms.iph, htons(ETH_P_TEB));
708c5441932SPravin B Shelar 	return NETDEV_TX_OK;
709c5441932SPravin B Shelar 
710c5441932SPravin B Shelar free_skb:
7113acfa1e7SEric Dumazet 	kfree_skb(skb);
712c5441932SPravin B Shelar 	dev->stats.tx_dropped++;
713c5441932SPravin B Shelar 	return NETDEV_TX_OK;
71468c33163SPravin B Shelar }
715ee34c1ebSMichal Schmidt 
716dd9d598cSXin Long static void ipgre_link_update(struct net_device *dev, bool set_mtu)
717dd9d598cSXin Long {
718dd9d598cSXin Long 	struct ip_tunnel *tunnel = netdev_priv(dev);
719dd9d598cSXin Long 	int len;
720dd9d598cSXin Long 
721dd9d598cSXin Long 	len = tunnel->tun_hlen;
722dd9d598cSXin Long 	tunnel->tun_hlen = gre_calc_hlen(tunnel->parms.o_flags);
723dd9d598cSXin Long 	len = tunnel->tun_hlen - len;
724dd9d598cSXin Long 	tunnel->hlen = tunnel->hlen + len;
725dd9d598cSXin Long 
726dd9d598cSXin Long 	dev->needed_headroom = dev->needed_headroom + len;
727dd9d598cSXin Long 	if (set_mtu)
728dd9d598cSXin Long 		dev->mtu = max_t(int, dev->mtu - len, 68);
729dd9d598cSXin Long 
730dd9d598cSXin Long 	if (!(tunnel->parms.o_flags & TUNNEL_SEQ)) {
731dd9d598cSXin Long 		if (!(tunnel->parms.o_flags & TUNNEL_CSUM) ||
732dd9d598cSXin Long 		    tunnel->encap.type == TUNNEL_ENCAP_NONE) {
733dd9d598cSXin Long 			dev->features |= NETIF_F_GSO_SOFTWARE;
734dd9d598cSXin Long 			dev->hw_features |= NETIF_F_GSO_SOFTWARE;
7351cc5954fSSabrina Dubroca 		} else {
7361cc5954fSSabrina Dubroca 			dev->features &= ~NETIF_F_GSO_SOFTWARE;
7371cc5954fSSabrina Dubroca 			dev->hw_features &= ~NETIF_F_GSO_SOFTWARE;
738dd9d598cSXin Long 		}
739dd9d598cSXin Long 		dev->features |= NETIF_F_LLTX;
7401cc5954fSSabrina Dubroca 	} else {
7411cc5954fSSabrina Dubroca 		dev->hw_features &= ~NETIF_F_GSO_SOFTWARE;
7421cc5954fSSabrina Dubroca 		dev->features &= ~(NETIF_F_LLTX | NETIF_F_GSO_SOFTWARE);
743dd9d598cSXin Long 	}
744dd9d598cSXin Long }
745dd9d598cSXin Long 
746c5441932SPravin B Shelar static int ipgre_tunnel_ioctl(struct net_device *dev,
747c5441932SPravin B Shelar 			      struct ifreq *ifr, int cmd)
7481da177e4SLinus Torvalds {
7491da177e4SLinus Torvalds 	struct ip_tunnel_parm p;
750a0efab67SXin Long 	int err;
7511da177e4SLinus Torvalds 
7521da177e4SLinus Torvalds 	if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
753c5441932SPravin B Shelar 		return -EFAULT;
754a0efab67SXin Long 
7556c734fb8SCong Wang 	if (cmd == SIOCADDTUNNEL || cmd == SIOCCHGTUNNEL) {
7561da177e4SLinus Torvalds 		if (p.iph.version != 4 || p.iph.protocol != IPPROTO_GRE ||
7571da177e4SLinus Torvalds 		    p.iph.ihl != 5 || (p.iph.frag_off & htons(~IP_DF)) ||
7586c734fb8SCong Wang 		    ((p.i_flags | p.o_flags) & (GRE_VERSION | GRE_ROUTING)))
7591da177e4SLinus Torvalds 			return -EINVAL;
760c5441932SPravin B Shelar 	}
761a0efab67SXin Long 
762c5441932SPravin B Shelar 	p.i_flags = gre_flags_to_tnl_flags(p.i_flags);
763c5441932SPravin B Shelar 	p.o_flags = gre_flags_to_tnl_flags(p.o_flags);
764c5441932SPravin B Shelar 
765c5441932SPravin B Shelar 	err = ip_tunnel_ioctl(dev, &p, cmd);
766c5441932SPravin B Shelar 	if (err)
767c5441932SPravin B Shelar 		return err;
768c5441932SPravin B Shelar 
769a0efab67SXin Long 	if (cmd == SIOCCHGTUNNEL) {
770a0efab67SXin Long 		struct ip_tunnel *t = netdev_priv(dev);
771a0efab67SXin Long 
772a0efab67SXin Long 		t->parms.i_flags = p.i_flags;
773a0efab67SXin Long 		t->parms.o_flags = p.o_flags;
774a0efab67SXin Long 
775a0efab67SXin Long 		if (strcmp(dev->rtnl_link_ops->kind, "erspan"))
776a0efab67SXin Long 			ipgre_link_update(dev, true);
777a0efab67SXin Long 	}
778a0efab67SXin Long 
77995f5c64cSTom Herbert 	p.i_flags = gre_tnl_flags_to_gre_flags(p.i_flags);
78095f5c64cSTom Herbert 	p.o_flags = gre_tnl_flags_to_gre_flags(p.o_flags);
781c5441932SPravin B Shelar 
782c5441932SPravin B Shelar 	if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p)))
783c5441932SPravin B Shelar 		return -EFAULT;
784a0efab67SXin Long 
7851da177e4SLinus Torvalds 	return 0;
7861da177e4SLinus Torvalds }
7871da177e4SLinus Torvalds 
7881da177e4SLinus Torvalds /* Nice toy. Unfortunately, useless in real life :-)
7891da177e4SLinus Torvalds    It allows to construct virtual multiprotocol broadcast "LAN"
7901da177e4SLinus Torvalds    over the Internet, provided multicast routing is tuned.
7911da177e4SLinus Torvalds 
7921da177e4SLinus Torvalds 
7931da177e4SLinus Torvalds    I have no idea was this bicycle invented before me,
7941da177e4SLinus Torvalds    so that I had to set ARPHRD_IPGRE to a random value.
7951da177e4SLinus Torvalds    I have an impression, that Cisco could make something similar,
7961da177e4SLinus Torvalds    but this feature is apparently missing in IOS<=11.2(8).
7971da177e4SLinus Torvalds 
7981da177e4SLinus Torvalds    I set up 10.66.66/24 and fec0:6666:6666::0/96 as virtual networks
7991da177e4SLinus Torvalds    with broadcast 224.66.66.66. If you have access to mbone, play with me :-)
8001da177e4SLinus Torvalds 
8011da177e4SLinus Torvalds    ping -t 255 224.66.66.66
8021da177e4SLinus Torvalds 
8031da177e4SLinus Torvalds    If nobody answers, mbone does not work.
8041da177e4SLinus Torvalds 
8051da177e4SLinus Torvalds    ip tunnel add Universe mode gre remote 224.66.66.66 local <Your_real_addr> ttl 255
8061da177e4SLinus Torvalds    ip addr add 10.66.66.<somewhat>/24 dev Universe
8071da177e4SLinus Torvalds    ifconfig Universe up
8081da177e4SLinus Torvalds    ifconfig Universe add fe80::<Your_real_addr>/10
8091da177e4SLinus Torvalds    ifconfig Universe add fec0:6666:6666::<Your_real_addr>/96
8101da177e4SLinus Torvalds    ftp 10.66.66.66
8111da177e4SLinus Torvalds    ...
8121da177e4SLinus Torvalds    ftp fec0:6666:6666::193.233.7.65
8131da177e4SLinus Torvalds    ...
8141da177e4SLinus Torvalds  */
8153b04dddeSStephen Hemminger static int ipgre_header(struct sk_buff *skb, struct net_device *dev,
8163b04dddeSStephen Hemminger 			unsigned short type,
8171507850bSEric Dumazet 			const void *daddr, const void *saddr, unsigned int len)
8181da177e4SLinus Torvalds {
8192941a486SPatrick McHardy 	struct ip_tunnel *t = netdev_priv(dev);
820c5441932SPravin B Shelar 	struct iphdr *iph;
821c5441932SPravin B Shelar 	struct gre_base_hdr *greh;
822c5441932SPravin B Shelar 
823d58ff351SJohannes Berg 	iph = skb_push(skb, t->hlen + sizeof(*iph));
824c5441932SPravin B Shelar 	greh = (struct gre_base_hdr *)(iph+1);
82595f5c64cSTom Herbert 	greh->flags = gre_tnl_flags_to_gre_flags(t->parms.o_flags);
826c5441932SPravin B Shelar 	greh->protocol = htons(type);
8271da177e4SLinus Torvalds 
8281da177e4SLinus Torvalds 	memcpy(iph, &t->parms.iph, sizeof(struct iphdr));
8291da177e4SLinus Torvalds 
830c5441932SPravin B Shelar 	/* Set the source hardware address. */
8311da177e4SLinus Torvalds 	if (saddr)
8321da177e4SLinus Torvalds 		memcpy(&iph->saddr, saddr, 4);
8336d55cb91STimo Teräs 	if (daddr)
8341da177e4SLinus Torvalds 		memcpy(&iph->daddr, daddr, 4);
8356d55cb91STimo Teräs 	if (iph->daddr)
83677a482bdSTimo Teräs 		return t->hlen + sizeof(*iph);
8371da177e4SLinus Torvalds 
838c5441932SPravin B Shelar 	return -(t->hlen + sizeof(*iph));
8391da177e4SLinus Torvalds }
8401da177e4SLinus Torvalds 
8416a5f44d7STimo Teras static int ipgre_header_parse(const struct sk_buff *skb, unsigned char *haddr)
8426a5f44d7STimo Teras {
843b71d1d42SEric Dumazet 	const struct iphdr *iph = (const struct iphdr *) skb_mac_header(skb);
8446a5f44d7STimo Teras 	memcpy(haddr, &iph->saddr, 4);
8456a5f44d7STimo Teras 	return 4;
8466a5f44d7STimo Teras }
8476a5f44d7STimo Teras 
8483b04dddeSStephen Hemminger static const struct header_ops ipgre_header_ops = {
8493b04dddeSStephen Hemminger 	.create	= ipgre_header,
8506a5f44d7STimo Teras 	.parse	= ipgre_header_parse,
8513b04dddeSStephen Hemminger };
8523b04dddeSStephen Hemminger 
8536a5f44d7STimo Teras #ifdef CONFIG_NET_IPGRE_BROADCAST
8541da177e4SLinus Torvalds static int ipgre_open(struct net_device *dev)
8551da177e4SLinus Torvalds {
8562941a486SPatrick McHardy 	struct ip_tunnel *t = netdev_priv(dev);
8571da177e4SLinus Torvalds 
858f97c1e0cSJoe Perches 	if (ipv4_is_multicast(t->parms.iph.daddr)) {
859cbb1e85fSDavid S. Miller 		struct flowi4 fl4;
860cbb1e85fSDavid S. Miller 		struct rtable *rt;
861cbb1e85fSDavid S. Miller 
862b57708adSNicolas Dichtel 		rt = ip_route_output_gre(t->net, &fl4,
86378fbfd8aSDavid S. Miller 					 t->parms.iph.daddr,
86478fbfd8aSDavid S. Miller 					 t->parms.iph.saddr,
86578fbfd8aSDavid S. Miller 					 t->parms.o_key,
86678fbfd8aSDavid S. Miller 					 RT_TOS(t->parms.iph.tos),
86778fbfd8aSDavid S. Miller 					 t->parms.link);
868b23dd4feSDavid S. Miller 		if (IS_ERR(rt))
8691da177e4SLinus Torvalds 			return -EADDRNOTAVAIL;
870d8d1f30bSChangli Gao 		dev = rt->dst.dev;
8711da177e4SLinus Torvalds 		ip_rt_put(rt);
87251456b29SIan Morris 		if (!__in_dev_get_rtnl(dev))
8731da177e4SLinus Torvalds 			return -EADDRNOTAVAIL;
8741da177e4SLinus Torvalds 		t->mlink = dev->ifindex;
875e5ed6399SHerbert Xu 		ip_mc_inc_group(__in_dev_get_rtnl(dev), t->parms.iph.daddr);
8761da177e4SLinus Torvalds 	}
8771da177e4SLinus Torvalds 	return 0;
8781da177e4SLinus Torvalds }
8791da177e4SLinus Torvalds 
8801da177e4SLinus Torvalds static int ipgre_close(struct net_device *dev)
8811da177e4SLinus Torvalds {
8822941a486SPatrick McHardy 	struct ip_tunnel *t = netdev_priv(dev);
883b8c26a33SStephen Hemminger 
884f97c1e0cSJoe Perches 	if (ipv4_is_multicast(t->parms.iph.daddr) && t->mlink) {
8857fee0ca2SDenis V. Lunev 		struct in_device *in_dev;
886b57708adSNicolas Dichtel 		in_dev = inetdev_by_index(t->net, t->mlink);
8878723e1b4SEric Dumazet 		if (in_dev)
8881da177e4SLinus Torvalds 			ip_mc_dec_group(in_dev, t->parms.iph.daddr);
8891da177e4SLinus Torvalds 	}
8901da177e4SLinus Torvalds 	return 0;
8911da177e4SLinus Torvalds }
8921da177e4SLinus Torvalds #endif
8931da177e4SLinus Torvalds 
894b8c26a33SStephen Hemminger static const struct net_device_ops ipgre_netdev_ops = {
895b8c26a33SStephen Hemminger 	.ndo_init		= ipgre_tunnel_init,
896c5441932SPravin B Shelar 	.ndo_uninit		= ip_tunnel_uninit,
897b8c26a33SStephen Hemminger #ifdef CONFIG_NET_IPGRE_BROADCAST
898b8c26a33SStephen Hemminger 	.ndo_open		= ipgre_open,
899b8c26a33SStephen Hemminger 	.ndo_stop		= ipgre_close,
900b8c26a33SStephen Hemminger #endif
901c5441932SPravin B Shelar 	.ndo_start_xmit		= ipgre_xmit,
902b8c26a33SStephen Hemminger 	.ndo_do_ioctl		= ipgre_tunnel_ioctl,
903c5441932SPravin B Shelar 	.ndo_change_mtu		= ip_tunnel_change_mtu,
904c5441932SPravin B Shelar 	.ndo_get_stats64	= ip_tunnel_get_stats64,
9051e99584bSNicolas Dichtel 	.ndo_get_iflink		= ip_tunnel_get_iflink,
906b8c26a33SStephen Hemminger };
907b8c26a33SStephen Hemminger 
9086b78f16eSEric Dumazet #define GRE_FEATURES (NETIF_F_SG |		\
9096b78f16eSEric Dumazet 		      NETIF_F_FRAGLIST |	\
9106b78f16eSEric Dumazet 		      NETIF_F_HIGHDMA |		\
9116b78f16eSEric Dumazet 		      NETIF_F_HW_CSUM)
9126b78f16eSEric Dumazet 
9131da177e4SLinus Torvalds static void ipgre_tunnel_setup(struct net_device *dev)
9141da177e4SLinus Torvalds {
915b8c26a33SStephen Hemminger 	dev->netdev_ops		= &ipgre_netdev_ops;
9165a455275SNicolas Dichtel 	dev->type		= ARPHRD_IPGRE;
917c5441932SPravin B Shelar 	ip_tunnel_setup(dev, ipgre_net_id);
918c5441932SPravin B Shelar }
9191da177e4SLinus Torvalds 
920c5441932SPravin B Shelar static void __gre_tunnel_init(struct net_device *dev)
921c5441932SPravin B Shelar {
922c5441932SPravin B Shelar 	struct ip_tunnel *tunnel;
923c5441932SPravin B Shelar 
924c5441932SPravin B Shelar 	tunnel = netdev_priv(dev);
92595f5c64cSTom Herbert 	tunnel->tun_hlen = gre_calc_hlen(tunnel->parms.o_flags);
926c5441932SPravin B Shelar 	tunnel->parms.iph.protocol = IPPROTO_GRE;
927c5441932SPravin B Shelar 
9284565e991STom Herbert 	tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen;
9294565e991STom Herbert 
930b57708adSNicolas Dichtel 	dev->features		|= GRE_FEATURES;
9316b78f16eSEric Dumazet 	dev->hw_features	|= GRE_FEATURES;
932c5441932SPravin B Shelar 
933c5441932SPravin B Shelar 	if (!(tunnel->parms.o_flags & TUNNEL_SEQ)) {
934a0ca153fSAlexander Duyck 		/* TCP offload with GRE SEQ is not supported, nor
935a0ca153fSAlexander Duyck 		 * can we support 2 levels of outer headers requiring
936a0ca153fSAlexander Duyck 		 * an update.
937a0ca153fSAlexander Duyck 		 */
938a0ca153fSAlexander Duyck 		if (!(tunnel->parms.o_flags & TUNNEL_CSUM) ||
939a0ca153fSAlexander Duyck 		    (tunnel->encap.type == TUNNEL_ENCAP_NONE)) {
940c5441932SPravin B Shelar 			dev->features    |= NETIF_F_GSO_SOFTWARE;
941c5441932SPravin B Shelar 			dev->hw_features |= NETIF_F_GSO_SOFTWARE;
942a0ca153fSAlexander Duyck 		}
943a0ca153fSAlexander Duyck 
944c5441932SPravin B Shelar 		/* Can use a lockless transmit, unless we generate
945c5441932SPravin B Shelar 		 * output sequences
946c5441932SPravin B Shelar 		 */
947c5441932SPravin B Shelar 		dev->features |= NETIF_F_LLTX;
948c5441932SPravin B Shelar 	}
9491da177e4SLinus Torvalds }
9501da177e4SLinus Torvalds 
9511da177e4SLinus Torvalds static int ipgre_tunnel_init(struct net_device *dev)
9521da177e4SLinus Torvalds {
953c5441932SPravin B Shelar 	struct ip_tunnel *tunnel = netdev_priv(dev);
954c5441932SPravin B Shelar 	struct iphdr *iph = &tunnel->parms.iph;
9551da177e4SLinus Torvalds 
956c5441932SPravin B Shelar 	__gre_tunnel_init(dev);
9571da177e4SLinus Torvalds 
958c5441932SPravin B Shelar 	memcpy(dev->dev_addr, &iph->saddr, 4);
959c5441932SPravin B Shelar 	memcpy(dev->broadcast, &iph->daddr, 4);
9601da177e4SLinus Torvalds 
961c5441932SPravin B Shelar 	dev->flags		= IFF_NOARP;
96202875878SEric Dumazet 	netif_keep_dst(dev);
963c5441932SPravin B Shelar 	dev->addr_len		= 4;
9641da177e4SLinus Torvalds 
965a64b04d8SJiri Benc 	if (iph->daddr && !tunnel->collect_md) {
9661da177e4SLinus Torvalds #ifdef CONFIG_NET_IPGRE_BROADCAST
967f97c1e0cSJoe Perches 		if (ipv4_is_multicast(iph->daddr)) {
9681da177e4SLinus Torvalds 			if (!iph->saddr)
9691da177e4SLinus Torvalds 				return -EINVAL;
9701da177e4SLinus Torvalds 			dev->flags = IFF_BROADCAST;
9713b04dddeSStephen Hemminger 			dev->header_ops = &ipgre_header_ops;
9721da177e4SLinus Torvalds 		}
9731da177e4SLinus Torvalds #endif
974a64b04d8SJiri Benc 	} else if (!tunnel->collect_md) {
9756a5f44d7STimo Teras 		dev->header_ops = &ipgre_header_ops;
976a64b04d8SJiri Benc 	}
9771da177e4SLinus Torvalds 
978c5441932SPravin B Shelar 	return ip_tunnel_init(dev);
97960769a5dSEric Dumazet }
98060769a5dSEric Dumazet 
9819f57c67cSPravin B Shelar static const struct gre_protocol ipgre_protocol = {
9829f57c67cSPravin B Shelar 	.handler     = gre_rcv,
9839f57c67cSPravin B Shelar 	.err_handler = gre_err,
9841da177e4SLinus Torvalds };
9851da177e4SLinus Torvalds 
9862c8c1e72SAlexey Dobriyan static int __net_init ipgre_init_net(struct net *net)
98759a4c759SPavel Emelyanov {
988c5441932SPravin B Shelar 	return ip_tunnel_init_net(net, ipgre_net_id, &ipgre_link_ops, NULL);
98959a4c759SPavel Emelyanov }
99059a4c759SPavel Emelyanov 
99164bc1781SEric Dumazet static void __net_exit ipgre_exit_batch_net(struct list_head *list_net)
99259a4c759SPavel Emelyanov {
99364bc1781SEric Dumazet 	ip_tunnel_delete_nets(list_net, ipgre_net_id, &ipgre_link_ops);
99459a4c759SPavel Emelyanov }
99559a4c759SPavel Emelyanov 
99659a4c759SPavel Emelyanov static struct pernet_operations ipgre_net_ops = {
99759a4c759SPavel Emelyanov 	.init = ipgre_init_net,
99864bc1781SEric Dumazet 	.exit_batch = ipgre_exit_batch_net,
999cfb8fbf2SEric W. Biederman 	.id   = &ipgre_net_id,
1000c5441932SPravin B Shelar 	.size = sizeof(struct ip_tunnel_net),
100159a4c759SPavel Emelyanov };
10021da177e4SLinus Torvalds 
1003a8b8a889SMatthias Schiffer static int ipgre_tunnel_validate(struct nlattr *tb[], struct nlattr *data[],
1004a8b8a889SMatthias Schiffer 				 struct netlink_ext_ack *extack)
1005c19e654dSHerbert Xu {
1006c19e654dSHerbert Xu 	__be16 flags;
1007c19e654dSHerbert Xu 
1008c19e654dSHerbert Xu 	if (!data)
1009c19e654dSHerbert Xu 		return 0;
1010c19e654dSHerbert Xu 
1011c19e654dSHerbert Xu 	flags = 0;
1012c19e654dSHerbert Xu 	if (data[IFLA_GRE_IFLAGS])
1013c19e654dSHerbert Xu 		flags |= nla_get_be16(data[IFLA_GRE_IFLAGS]);
1014c19e654dSHerbert Xu 	if (data[IFLA_GRE_OFLAGS])
1015c19e654dSHerbert Xu 		flags |= nla_get_be16(data[IFLA_GRE_OFLAGS]);
1016c19e654dSHerbert Xu 	if (flags & (GRE_VERSION|GRE_ROUTING))
1017c19e654dSHerbert Xu 		return -EINVAL;
1018c19e654dSHerbert Xu 
1019946b636fSJiri Benc 	if (data[IFLA_GRE_COLLECT_METADATA] &&
1020946b636fSJiri Benc 	    data[IFLA_GRE_ENCAP_TYPE] &&
1021946b636fSJiri Benc 	    nla_get_u16(data[IFLA_GRE_ENCAP_TYPE]) != TUNNEL_ENCAP_NONE)
1022946b636fSJiri Benc 		return -EINVAL;
1023946b636fSJiri Benc 
1024c19e654dSHerbert Xu 	return 0;
1025c19e654dSHerbert Xu }
1026c19e654dSHerbert Xu 
1027a8b8a889SMatthias Schiffer static int ipgre_tap_validate(struct nlattr *tb[], struct nlattr *data[],
1028a8b8a889SMatthias Schiffer 			      struct netlink_ext_ack *extack)
1029e1a80002SHerbert Xu {
1030e1a80002SHerbert Xu 	__be32 daddr;
1031e1a80002SHerbert Xu 
1032e1a80002SHerbert Xu 	if (tb[IFLA_ADDRESS]) {
1033e1a80002SHerbert Xu 		if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN)
1034e1a80002SHerbert Xu 			return -EINVAL;
1035e1a80002SHerbert Xu 		if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS])))
1036e1a80002SHerbert Xu 			return -EADDRNOTAVAIL;
1037e1a80002SHerbert Xu 	}
1038e1a80002SHerbert Xu 
1039e1a80002SHerbert Xu 	if (!data)
1040e1a80002SHerbert Xu 		goto out;
1041e1a80002SHerbert Xu 
1042e1a80002SHerbert Xu 	if (data[IFLA_GRE_REMOTE]) {
1043e1a80002SHerbert Xu 		memcpy(&daddr, nla_data(data[IFLA_GRE_REMOTE]), 4);
1044e1a80002SHerbert Xu 		if (!daddr)
1045e1a80002SHerbert Xu 			return -EINVAL;
1046e1a80002SHerbert Xu 	}
1047e1a80002SHerbert Xu 
1048e1a80002SHerbert Xu out:
1049a8b8a889SMatthias Schiffer 	return ipgre_tunnel_validate(tb, data, extack);
1050e1a80002SHerbert Xu }
1051e1a80002SHerbert Xu 
105284e54fe0SWilliam Tu static int erspan_validate(struct nlattr *tb[], struct nlattr *data[],
105384e54fe0SWilliam Tu 			   struct netlink_ext_ack *extack)
105484e54fe0SWilliam Tu {
105584e54fe0SWilliam Tu 	__be16 flags = 0;
105684e54fe0SWilliam Tu 	int ret;
105784e54fe0SWilliam Tu 
105884e54fe0SWilliam Tu 	if (!data)
105984e54fe0SWilliam Tu 		return 0;
106084e54fe0SWilliam Tu 
106184e54fe0SWilliam Tu 	ret = ipgre_tap_validate(tb, data, extack);
106284e54fe0SWilliam Tu 	if (ret)
106384e54fe0SWilliam Tu 		return ret;
106484e54fe0SWilliam Tu 
106584e54fe0SWilliam Tu 	/* ERSPAN should only have GRE sequence and key flag */
10661a66a836SWilliam Tu 	if (data[IFLA_GRE_OFLAGS])
106784e54fe0SWilliam Tu 		flags |= nla_get_be16(data[IFLA_GRE_OFLAGS]);
10681a66a836SWilliam Tu 	if (data[IFLA_GRE_IFLAGS])
106984e54fe0SWilliam Tu 		flags |= nla_get_be16(data[IFLA_GRE_IFLAGS]);
10701a66a836SWilliam Tu 	if (!data[IFLA_GRE_COLLECT_METADATA] &&
10711a66a836SWilliam Tu 	    flags != (GRE_SEQ | GRE_KEY))
107284e54fe0SWilliam Tu 		return -EINVAL;
107384e54fe0SWilliam Tu 
107484e54fe0SWilliam Tu 	/* ERSPAN Session ID only has 10-bit. Since we reuse
107584e54fe0SWilliam Tu 	 * 32-bit key field as ID, check it's range.
107684e54fe0SWilliam Tu 	 */
107784e54fe0SWilliam Tu 	if (data[IFLA_GRE_IKEY] &&
107884e54fe0SWilliam Tu 	    (ntohl(nla_get_be32(data[IFLA_GRE_IKEY])) & ~ID_MASK))
107984e54fe0SWilliam Tu 		return -EINVAL;
108084e54fe0SWilliam Tu 
108184e54fe0SWilliam Tu 	if (data[IFLA_GRE_OKEY] &&
108284e54fe0SWilliam Tu 	    (ntohl(nla_get_be32(data[IFLA_GRE_OKEY])) & ~ID_MASK))
108384e54fe0SWilliam Tu 		return -EINVAL;
108484e54fe0SWilliam Tu 
108584e54fe0SWilliam Tu 	return 0;
108684e54fe0SWilliam Tu }
108784e54fe0SWilliam Tu 
108822a59be8SPhilip Prindeville static int ipgre_netlink_parms(struct net_device *dev,
10892e15ea39SPravin B Shelar 				struct nlattr *data[],
10902e15ea39SPravin B Shelar 				struct nlattr *tb[],
10919830ad4cSCraig Gallek 				struct ip_tunnel_parm *parms,
10929830ad4cSCraig Gallek 				__u32 *fwmark)
1093c19e654dSHerbert Xu {
109422a59be8SPhilip Prindeville 	struct ip_tunnel *t = netdev_priv(dev);
109522a59be8SPhilip Prindeville 
10967bb82d92SHerbert Xu 	memset(parms, 0, sizeof(*parms));
1097c19e654dSHerbert Xu 
1098c19e654dSHerbert Xu 	parms->iph.protocol = IPPROTO_GRE;
1099c19e654dSHerbert Xu 
1100c19e654dSHerbert Xu 	if (!data)
110122a59be8SPhilip Prindeville 		return 0;
1102c19e654dSHerbert Xu 
1103c19e654dSHerbert Xu 	if (data[IFLA_GRE_LINK])
1104c19e654dSHerbert Xu 		parms->link = nla_get_u32(data[IFLA_GRE_LINK]);
1105c19e654dSHerbert Xu 
1106c19e654dSHerbert Xu 	if (data[IFLA_GRE_IFLAGS])
1107c5441932SPravin B Shelar 		parms->i_flags = gre_flags_to_tnl_flags(nla_get_be16(data[IFLA_GRE_IFLAGS]));
1108c19e654dSHerbert Xu 
1109c19e654dSHerbert Xu 	if (data[IFLA_GRE_OFLAGS])
1110c5441932SPravin B Shelar 		parms->o_flags = gre_flags_to_tnl_flags(nla_get_be16(data[IFLA_GRE_OFLAGS]));
1111c19e654dSHerbert Xu 
1112c19e654dSHerbert Xu 	if (data[IFLA_GRE_IKEY])
1113c19e654dSHerbert Xu 		parms->i_key = nla_get_be32(data[IFLA_GRE_IKEY]);
1114c19e654dSHerbert Xu 
1115c19e654dSHerbert Xu 	if (data[IFLA_GRE_OKEY])
1116c19e654dSHerbert Xu 		parms->o_key = nla_get_be32(data[IFLA_GRE_OKEY]);
1117c19e654dSHerbert Xu 
1118c19e654dSHerbert Xu 	if (data[IFLA_GRE_LOCAL])
111967b61f6cSJiri Benc 		parms->iph.saddr = nla_get_in_addr(data[IFLA_GRE_LOCAL]);
1120c19e654dSHerbert Xu 
1121c19e654dSHerbert Xu 	if (data[IFLA_GRE_REMOTE])
112267b61f6cSJiri Benc 		parms->iph.daddr = nla_get_in_addr(data[IFLA_GRE_REMOTE]);
1123c19e654dSHerbert Xu 
1124c19e654dSHerbert Xu 	if (data[IFLA_GRE_TTL])
1125c19e654dSHerbert Xu 		parms->iph.ttl = nla_get_u8(data[IFLA_GRE_TTL]);
1126c19e654dSHerbert Xu 
1127c19e654dSHerbert Xu 	if (data[IFLA_GRE_TOS])
1128c19e654dSHerbert Xu 		parms->iph.tos = nla_get_u8(data[IFLA_GRE_TOS]);
1129c19e654dSHerbert Xu 
113022a59be8SPhilip Prindeville 	if (!data[IFLA_GRE_PMTUDISC] || nla_get_u8(data[IFLA_GRE_PMTUDISC])) {
113122a59be8SPhilip Prindeville 		if (t->ignore_df)
113222a59be8SPhilip Prindeville 			return -EINVAL;
1133c19e654dSHerbert Xu 		parms->iph.frag_off = htons(IP_DF);
113422a59be8SPhilip Prindeville 	}
11352e15ea39SPravin B Shelar 
11362e15ea39SPravin B Shelar 	if (data[IFLA_GRE_COLLECT_METADATA]) {
11372e15ea39SPravin B Shelar 		t->collect_md = true;
1138e271c7b4SJiri Benc 		if (dev->type == ARPHRD_IPGRE)
1139e271c7b4SJiri Benc 			dev->type = ARPHRD_NONE;
11402e15ea39SPravin B Shelar 	}
114122a59be8SPhilip Prindeville 
114222a59be8SPhilip Prindeville 	if (data[IFLA_GRE_IGNORE_DF]) {
114322a59be8SPhilip Prindeville 		if (nla_get_u8(data[IFLA_GRE_IGNORE_DF])
114422a59be8SPhilip Prindeville 		  && (parms->iph.frag_off & htons(IP_DF)))
114522a59be8SPhilip Prindeville 			return -EINVAL;
114622a59be8SPhilip Prindeville 		t->ignore_df = !!nla_get_u8(data[IFLA_GRE_IGNORE_DF]);
114722a59be8SPhilip Prindeville 	}
114822a59be8SPhilip Prindeville 
11499830ad4cSCraig Gallek 	if (data[IFLA_GRE_FWMARK])
11509830ad4cSCraig Gallek 		*fwmark = nla_get_u32(data[IFLA_GRE_FWMARK]);
11519830ad4cSCraig Gallek 
1152f551c91dSWilliam Tu 	if (data[IFLA_GRE_ERSPAN_VER]) {
1153f551c91dSWilliam Tu 		t->erspan_ver = nla_get_u8(data[IFLA_GRE_ERSPAN_VER]);
1154f551c91dSWilliam Tu 
1155f551c91dSWilliam Tu 		if (t->erspan_ver != 1 && t->erspan_ver != 2)
1156f551c91dSWilliam Tu 			return -EINVAL;
1157f551c91dSWilliam Tu 	}
1158f551c91dSWilliam Tu 
1159f551c91dSWilliam Tu 	if (t->erspan_ver == 1) {
116084e54fe0SWilliam Tu 		if (data[IFLA_GRE_ERSPAN_INDEX]) {
116184e54fe0SWilliam Tu 			t->index = nla_get_u32(data[IFLA_GRE_ERSPAN_INDEX]);
116284e54fe0SWilliam Tu 			if (t->index & ~INDEX_MASK)
116384e54fe0SWilliam Tu 				return -EINVAL;
116484e54fe0SWilliam Tu 		}
1165f551c91dSWilliam Tu 	} else if (t->erspan_ver == 2) {
1166f551c91dSWilliam Tu 		if (data[IFLA_GRE_ERSPAN_DIR]) {
1167f551c91dSWilliam Tu 			t->dir = nla_get_u8(data[IFLA_GRE_ERSPAN_DIR]);
1168f551c91dSWilliam Tu 			if (t->dir & ~(DIR_MASK >> DIR_OFFSET))
1169f551c91dSWilliam Tu 				return -EINVAL;
1170f551c91dSWilliam Tu 		}
1171f551c91dSWilliam Tu 		if (data[IFLA_GRE_ERSPAN_HWID]) {
1172f551c91dSWilliam Tu 			t->hwid = nla_get_u16(data[IFLA_GRE_ERSPAN_HWID]);
1173f551c91dSWilliam Tu 			if (t->hwid & ~(HWID_MASK >> HWID_OFFSET))
1174f551c91dSWilliam Tu 				return -EINVAL;
1175f551c91dSWilliam Tu 		}
1176f551c91dSWilliam Tu 	}
117784e54fe0SWilliam Tu 
117822a59be8SPhilip Prindeville 	return 0;
1179c19e654dSHerbert Xu }
1180c19e654dSHerbert Xu 
11814565e991STom Herbert /* This function returns true when ENCAP attributes are present in the nl msg */
11824565e991STom Herbert static bool ipgre_netlink_encap_parms(struct nlattr *data[],
11834565e991STom Herbert 				      struct ip_tunnel_encap *ipencap)
11844565e991STom Herbert {
11854565e991STom Herbert 	bool ret = false;
11864565e991STom Herbert 
11874565e991STom Herbert 	memset(ipencap, 0, sizeof(*ipencap));
11884565e991STom Herbert 
11894565e991STom Herbert 	if (!data)
11904565e991STom Herbert 		return ret;
11914565e991STom Herbert 
11924565e991STom Herbert 	if (data[IFLA_GRE_ENCAP_TYPE]) {
11934565e991STom Herbert 		ret = true;
11944565e991STom Herbert 		ipencap->type = nla_get_u16(data[IFLA_GRE_ENCAP_TYPE]);
11954565e991STom Herbert 	}
11964565e991STom Herbert 
11974565e991STom Herbert 	if (data[IFLA_GRE_ENCAP_FLAGS]) {
11984565e991STom Herbert 		ret = true;
11994565e991STom Herbert 		ipencap->flags = nla_get_u16(data[IFLA_GRE_ENCAP_FLAGS]);
12004565e991STom Herbert 	}
12014565e991STom Herbert 
12024565e991STom Herbert 	if (data[IFLA_GRE_ENCAP_SPORT]) {
12034565e991STom Herbert 		ret = true;
12043e97fa70SSabrina Dubroca 		ipencap->sport = nla_get_be16(data[IFLA_GRE_ENCAP_SPORT]);
12054565e991STom Herbert 	}
12064565e991STom Herbert 
12074565e991STom Herbert 	if (data[IFLA_GRE_ENCAP_DPORT]) {
12084565e991STom Herbert 		ret = true;
12093e97fa70SSabrina Dubroca 		ipencap->dport = nla_get_be16(data[IFLA_GRE_ENCAP_DPORT]);
12104565e991STom Herbert 	}
12114565e991STom Herbert 
12124565e991STom Herbert 	return ret;
12134565e991STom Herbert }
12144565e991STom Herbert 
1215c5441932SPravin B Shelar static int gre_tap_init(struct net_device *dev)
1216e1a80002SHerbert Xu {
1217c5441932SPravin B Shelar 	__gre_tunnel_init(dev);
1218bec94d43Sstephen hemminger 	dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
1219d51711c0SXin Long 	netif_keep_dst(dev);
1220e1a80002SHerbert Xu 
1221c5441932SPravin B Shelar 	return ip_tunnel_init(dev);
1222e1a80002SHerbert Xu }
1223e1a80002SHerbert Xu 
1224c5441932SPravin B Shelar static const struct net_device_ops gre_tap_netdev_ops = {
1225c5441932SPravin B Shelar 	.ndo_init		= gre_tap_init,
1226c5441932SPravin B Shelar 	.ndo_uninit		= ip_tunnel_uninit,
1227c5441932SPravin B Shelar 	.ndo_start_xmit		= gre_tap_xmit,
1228b8c26a33SStephen Hemminger 	.ndo_set_mac_address 	= eth_mac_addr,
1229b8c26a33SStephen Hemminger 	.ndo_validate_addr	= eth_validate_addr,
1230c5441932SPravin B Shelar 	.ndo_change_mtu		= ip_tunnel_change_mtu,
1231c5441932SPravin B Shelar 	.ndo_get_stats64	= ip_tunnel_get_stats64,
12321e99584bSNicolas Dichtel 	.ndo_get_iflink		= ip_tunnel_get_iflink,
1233fc4099f1SPravin B Shelar 	.ndo_fill_metadata_dst	= gre_fill_metadata_dst,
1234b8c26a33SStephen Hemminger };
1235b8c26a33SStephen Hemminger 
123684e54fe0SWilliam Tu static int erspan_tunnel_init(struct net_device *dev)
123784e54fe0SWilliam Tu {
123884e54fe0SWilliam Tu 	struct ip_tunnel *tunnel = netdev_priv(dev);
123984e54fe0SWilliam Tu 
124084e54fe0SWilliam Tu 	tunnel->tun_hlen = 8;
124184e54fe0SWilliam Tu 	tunnel->parms.iph.protocol = IPPROTO_GRE;
1242c122fda2SXin Long 	tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen +
1243f551c91dSWilliam Tu 		       erspan_hdr_len(tunnel->erspan_ver);
124484e54fe0SWilliam Tu 
124584e54fe0SWilliam Tu 	dev->features		|= GRE_FEATURES;
124684e54fe0SWilliam Tu 	dev->hw_features	|= GRE_FEATURES;
124784e54fe0SWilliam Tu 	dev->priv_flags		|= IFF_LIVE_ADDR_CHANGE;
1248c84bed44SXin Long 	netif_keep_dst(dev);
124984e54fe0SWilliam Tu 
125084e54fe0SWilliam Tu 	return ip_tunnel_init(dev);
125184e54fe0SWilliam Tu }
125284e54fe0SWilliam Tu 
125384e54fe0SWilliam Tu static const struct net_device_ops erspan_netdev_ops = {
125484e54fe0SWilliam Tu 	.ndo_init		= erspan_tunnel_init,
125584e54fe0SWilliam Tu 	.ndo_uninit		= ip_tunnel_uninit,
125684e54fe0SWilliam Tu 	.ndo_start_xmit		= erspan_xmit,
125784e54fe0SWilliam Tu 	.ndo_set_mac_address	= eth_mac_addr,
125884e54fe0SWilliam Tu 	.ndo_validate_addr	= eth_validate_addr,
125984e54fe0SWilliam Tu 	.ndo_change_mtu		= ip_tunnel_change_mtu,
126084e54fe0SWilliam Tu 	.ndo_get_stats64	= ip_tunnel_get_stats64,
126184e54fe0SWilliam Tu 	.ndo_get_iflink		= ip_tunnel_get_iflink,
126284e54fe0SWilliam Tu 	.ndo_fill_metadata_dst	= gre_fill_metadata_dst,
126384e54fe0SWilliam Tu };
126484e54fe0SWilliam Tu 
1265e1a80002SHerbert Xu static void ipgre_tap_setup(struct net_device *dev)
1266e1a80002SHerbert Xu {
1267e1a80002SHerbert Xu 	ether_setup(dev);
1268cfddd4c3SXin Long 	dev->max_mtu = 0;
1269c5441932SPravin B Shelar 	dev->netdev_ops	= &gre_tap_netdev_ops;
1270d13b161cSJiri Benc 	dev->priv_flags &= ~IFF_TX_SKB_SHARING;
1271f8c1b7ceSstephen hemminger 	dev->priv_flags	|= IFF_LIVE_ADDR_CHANGE;
1272c5441932SPravin B Shelar 	ip_tunnel_setup(dev, gre_tap_net_id);
1273e1a80002SHerbert Xu }
1274e1a80002SHerbert Xu 
1275c5441932SPravin B Shelar static int ipgre_newlink(struct net *src_net, struct net_device *dev,
12767a3f4a18SMatthias Schiffer 			 struct nlattr *tb[], struct nlattr *data[],
12777a3f4a18SMatthias Schiffer 			 struct netlink_ext_ack *extack)
1278c19e654dSHerbert Xu {
1279c5441932SPravin B Shelar 	struct ip_tunnel_parm p;
12804565e991STom Herbert 	struct ip_tunnel_encap ipencap;
12819830ad4cSCraig Gallek 	__u32 fwmark = 0;
128222a59be8SPhilip Prindeville 	int err;
12834565e991STom Herbert 
12844565e991STom Herbert 	if (ipgre_netlink_encap_parms(data, &ipencap)) {
12854565e991STom Herbert 		struct ip_tunnel *t = netdev_priv(dev);
128622a59be8SPhilip Prindeville 		err = ip_tunnel_encap_setup(t, &ipencap);
12874565e991STom Herbert 
12884565e991STom Herbert 		if (err < 0)
12894565e991STom Herbert 			return err;
12904565e991STom Herbert 	}
1291c19e654dSHerbert Xu 
12929830ad4cSCraig Gallek 	err = ipgre_netlink_parms(dev, data, tb, &p, &fwmark);
129322a59be8SPhilip Prindeville 	if (err < 0)
129422a59be8SPhilip Prindeville 		return err;
12959830ad4cSCraig Gallek 	return ip_tunnel_newlink(dev, tb, &p, fwmark);
1296c19e654dSHerbert Xu }
1297c19e654dSHerbert Xu 
1298c19e654dSHerbert Xu static int ipgre_changelink(struct net_device *dev, struct nlattr *tb[],
1299ad744b22SMatthias Schiffer 			    struct nlattr *data[],
1300ad744b22SMatthias Schiffer 			    struct netlink_ext_ack *extack)
1301c19e654dSHerbert Xu {
13029830ad4cSCraig Gallek 	struct ip_tunnel *t = netdev_priv(dev);
13034565e991STom Herbert 	struct ip_tunnel_encap ipencap;
13049830ad4cSCraig Gallek 	__u32 fwmark = t->fwmark;
1305dd9d598cSXin Long 	struct ip_tunnel_parm p;
130622a59be8SPhilip Prindeville 	int err;
13074565e991STom Herbert 
13084565e991STom Herbert 	if (ipgre_netlink_encap_parms(data, &ipencap)) {
130922a59be8SPhilip Prindeville 		err = ip_tunnel_encap_setup(t, &ipencap);
13104565e991STom Herbert 
13114565e991STom Herbert 		if (err < 0)
13124565e991STom Herbert 			return err;
13134565e991STom Herbert 	}
1314c19e654dSHerbert Xu 
13159830ad4cSCraig Gallek 	err = ipgre_netlink_parms(dev, data, tb, &p, &fwmark);
131622a59be8SPhilip Prindeville 	if (err < 0)
131722a59be8SPhilip Prindeville 		return err;
1318dd9d598cSXin Long 
1319dd9d598cSXin Long 	err = ip_tunnel_changelink(dev, tb, &p, fwmark);
1320dd9d598cSXin Long 	if (err < 0)
1321dd9d598cSXin Long 		return err;
1322dd9d598cSXin Long 
1323dd9d598cSXin Long 	t->parms.i_flags = p.i_flags;
1324dd9d598cSXin Long 	t->parms.o_flags = p.o_flags;
1325dd9d598cSXin Long 
1326dd9d598cSXin Long 	if (strcmp(dev->rtnl_link_ops->kind, "erspan"))
1327dd9d598cSXin Long 		ipgre_link_update(dev, !tb[IFLA_MTU]);
1328dd9d598cSXin Long 
1329dd9d598cSXin Long 	return 0;
1330c19e654dSHerbert Xu }
1331c19e654dSHerbert Xu 
1332c19e654dSHerbert Xu static size_t ipgre_get_size(const struct net_device *dev)
1333c19e654dSHerbert Xu {
1334c19e654dSHerbert Xu 	return
1335c19e654dSHerbert Xu 		/* IFLA_GRE_LINK */
1336c19e654dSHerbert Xu 		nla_total_size(4) +
1337c19e654dSHerbert Xu 		/* IFLA_GRE_IFLAGS */
1338c19e654dSHerbert Xu 		nla_total_size(2) +
1339c19e654dSHerbert Xu 		/* IFLA_GRE_OFLAGS */
1340c19e654dSHerbert Xu 		nla_total_size(2) +
1341c19e654dSHerbert Xu 		/* IFLA_GRE_IKEY */
1342c19e654dSHerbert Xu 		nla_total_size(4) +
1343c19e654dSHerbert Xu 		/* IFLA_GRE_OKEY */
1344c19e654dSHerbert Xu 		nla_total_size(4) +
1345c19e654dSHerbert Xu 		/* IFLA_GRE_LOCAL */
1346c19e654dSHerbert Xu 		nla_total_size(4) +
1347c19e654dSHerbert Xu 		/* IFLA_GRE_REMOTE */
1348c19e654dSHerbert Xu 		nla_total_size(4) +
1349c19e654dSHerbert Xu 		/* IFLA_GRE_TTL */
1350c19e654dSHerbert Xu 		nla_total_size(1) +
1351c19e654dSHerbert Xu 		/* IFLA_GRE_TOS */
1352c19e654dSHerbert Xu 		nla_total_size(1) +
1353c19e654dSHerbert Xu 		/* IFLA_GRE_PMTUDISC */
1354c19e654dSHerbert Xu 		nla_total_size(1) +
13554565e991STom Herbert 		/* IFLA_GRE_ENCAP_TYPE */
13564565e991STom Herbert 		nla_total_size(2) +
13574565e991STom Herbert 		/* IFLA_GRE_ENCAP_FLAGS */
13584565e991STom Herbert 		nla_total_size(2) +
13594565e991STom Herbert 		/* IFLA_GRE_ENCAP_SPORT */
13604565e991STom Herbert 		nla_total_size(2) +
13614565e991STom Herbert 		/* IFLA_GRE_ENCAP_DPORT */
13624565e991STom Herbert 		nla_total_size(2) +
13632e15ea39SPravin B Shelar 		/* IFLA_GRE_COLLECT_METADATA */
13642e15ea39SPravin B Shelar 		nla_total_size(0) +
136522a59be8SPhilip Prindeville 		/* IFLA_GRE_IGNORE_DF */
136622a59be8SPhilip Prindeville 		nla_total_size(1) +
13679830ad4cSCraig Gallek 		/* IFLA_GRE_FWMARK */
13689830ad4cSCraig Gallek 		nla_total_size(4) +
136984e54fe0SWilliam Tu 		/* IFLA_GRE_ERSPAN_INDEX */
137084e54fe0SWilliam Tu 		nla_total_size(4) +
1371f551c91dSWilliam Tu 		/* IFLA_GRE_ERSPAN_VER */
1372f551c91dSWilliam Tu 		nla_total_size(1) +
1373f551c91dSWilliam Tu 		/* IFLA_GRE_ERSPAN_DIR */
1374f551c91dSWilliam Tu 		nla_total_size(1) +
1375f551c91dSWilliam Tu 		/* IFLA_GRE_ERSPAN_HWID */
1376f551c91dSWilliam Tu 		nla_total_size(2) +
1377c19e654dSHerbert Xu 		0;
1378c19e654dSHerbert Xu }
1379c19e654dSHerbert Xu 
1380c19e654dSHerbert Xu static int ipgre_fill_info(struct sk_buff *skb, const struct net_device *dev)
1381c19e654dSHerbert Xu {
1382c19e654dSHerbert Xu 	struct ip_tunnel *t = netdev_priv(dev);
1383c19e654dSHerbert Xu 	struct ip_tunnel_parm *p = &t->parms;
1384feaf5c79SLorenzo Bianconi 	__be16 o_flags = p->o_flags;
1385feaf5c79SLorenzo Bianconi 
13862bdf700eSLorenzo Bianconi 	if (t->erspan_ver == 1 || t->erspan_ver == 2) {
13872bdf700eSLorenzo Bianconi 		if (!t->collect_md)
1388feaf5c79SLorenzo Bianconi 			o_flags |= TUNNEL_KEY;
1389c19e654dSHerbert Xu 
13902bdf700eSLorenzo Bianconi 		if (nla_put_u8(skb, IFLA_GRE_ERSPAN_VER, t->erspan_ver))
13912bdf700eSLorenzo Bianconi 			goto nla_put_failure;
13922bdf700eSLorenzo Bianconi 
13932bdf700eSLorenzo Bianconi 		if (t->erspan_ver == 1) {
13942bdf700eSLorenzo Bianconi 			if (nla_put_u32(skb, IFLA_GRE_ERSPAN_INDEX, t->index))
13952bdf700eSLorenzo Bianconi 				goto nla_put_failure;
13962bdf700eSLorenzo Bianconi 		} else {
13972bdf700eSLorenzo Bianconi 			if (nla_put_u8(skb, IFLA_GRE_ERSPAN_DIR, t->dir))
13982bdf700eSLorenzo Bianconi 				goto nla_put_failure;
13992bdf700eSLorenzo Bianconi 			if (nla_put_u16(skb, IFLA_GRE_ERSPAN_HWID, t->hwid))
14002bdf700eSLorenzo Bianconi 				goto nla_put_failure;
14012bdf700eSLorenzo Bianconi 		}
14022bdf700eSLorenzo Bianconi 	}
14032bdf700eSLorenzo Bianconi 
1404f3756b79SDavid S. Miller 	if (nla_put_u32(skb, IFLA_GRE_LINK, p->link) ||
140595f5c64cSTom Herbert 	    nla_put_be16(skb, IFLA_GRE_IFLAGS,
140695f5c64cSTom Herbert 			 gre_tnl_flags_to_gre_flags(p->i_flags)) ||
140795f5c64cSTom Herbert 	    nla_put_be16(skb, IFLA_GRE_OFLAGS,
1408feaf5c79SLorenzo Bianconi 			 gre_tnl_flags_to_gre_flags(o_flags)) ||
1409f3756b79SDavid S. Miller 	    nla_put_be32(skb, IFLA_GRE_IKEY, p->i_key) ||
1410f3756b79SDavid S. Miller 	    nla_put_be32(skb, IFLA_GRE_OKEY, p->o_key) ||
1411930345eaSJiri Benc 	    nla_put_in_addr(skb, IFLA_GRE_LOCAL, p->iph.saddr) ||
1412930345eaSJiri Benc 	    nla_put_in_addr(skb, IFLA_GRE_REMOTE, p->iph.daddr) ||
1413f3756b79SDavid S. Miller 	    nla_put_u8(skb, IFLA_GRE_TTL, p->iph.ttl) ||
1414f3756b79SDavid S. Miller 	    nla_put_u8(skb, IFLA_GRE_TOS, p->iph.tos) ||
1415f3756b79SDavid S. Miller 	    nla_put_u8(skb, IFLA_GRE_PMTUDISC,
14169830ad4cSCraig Gallek 		       !!(p->iph.frag_off & htons(IP_DF))) ||
14179830ad4cSCraig Gallek 	    nla_put_u32(skb, IFLA_GRE_FWMARK, t->fwmark))
1418f3756b79SDavid S. Miller 		goto nla_put_failure;
14194565e991STom Herbert 
14204565e991STom Herbert 	if (nla_put_u16(skb, IFLA_GRE_ENCAP_TYPE,
14214565e991STom Herbert 			t->encap.type) ||
14223e97fa70SSabrina Dubroca 	    nla_put_be16(skb, IFLA_GRE_ENCAP_SPORT,
14234565e991STom Herbert 			 t->encap.sport) ||
14243e97fa70SSabrina Dubroca 	    nla_put_be16(skb, IFLA_GRE_ENCAP_DPORT,
14254565e991STom Herbert 			 t->encap.dport) ||
14264565e991STom Herbert 	    nla_put_u16(skb, IFLA_GRE_ENCAP_FLAGS,
1427e1b2cb65STom Herbert 			t->encap.flags))
14284565e991STom Herbert 		goto nla_put_failure;
14294565e991STom Herbert 
143022a59be8SPhilip Prindeville 	if (nla_put_u8(skb, IFLA_GRE_IGNORE_DF, t->ignore_df))
143122a59be8SPhilip Prindeville 		goto nla_put_failure;
143222a59be8SPhilip Prindeville 
14332e15ea39SPravin B Shelar 	if (t->collect_md) {
14342e15ea39SPravin B Shelar 		if (nla_put_flag(skb, IFLA_GRE_COLLECT_METADATA))
14352e15ea39SPravin B Shelar 			goto nla_put_failure;
14362e15ea39SPravin B Shelar 	}
14372e15ea39SPravin B Shelar 
1438c19e654dSHerbert Xu 	return 0;
1439c19e654dSHerbert Xu 
1440c19e654dSHerbert Xu nla_put_failure:
1441c19e654dSHerbert Xu 	return -EMSGSIZE;
1442c19e654dSHerbert Xu }
1443c19e654dSHerbert Xu 
144484e54fe0SWilliam Tu static void erspan_setup(struct net_device *dev)
144584e54fe0SWilliam Tu {
144684581bdaSXin Long 	struct ip_tunnel *t = netdev_priv(dev);
144784581bdaSXin Long 
144884e54fe0SWilliam Tu 	ether_setup(dev);
144984e54fe0SWilliam Tu 	dev->netdev_ops = &erspan_netdev_ops;
145084e54fe0SWilliam Tu 	dev->priv_flags &= ~IFF_TX_SKB_SHARING;
145184e54fe0SWilliam Tu 	dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
145284e54fe0SWilliam Tu 	ip_tunnel_setup(dev, erspan_net_id);
145384581bdaSXin Long 	t->erspan_ver = 1;
145484e54fe0SWilliam Tu }
145584e54fe0SWilliam Tu 
1456c19e654dSHerbert Xu static const struct nla_policy ipgre_policy[IFLA_GRE_MAX + 1] = {
1457c19e654dSHerbert Xu 	[IFLA_GRE_LINK]		= { .type = NLA_U32 },
1458c19e654dSHerbert Xu 	[IFLA_GRE_IFLAGS]	= { .type = NLA_U16 },
1459c19e654dSHerbert Xu 	[IFLA_GRE_OFLAGS]	= { .type = NLA_U16 },
1460c19e654dSHerbert Xu 	[IFLA_GRE_IKEY]		= { .type = NLA_U32 },
1461c19e654dSHerbert Xu 	[IFLA_GRE_OKEY]		= { .type = NLA_U32 },
14624d74f8baSPatrick McHardy 	[IFLA_GRE_LOCAL]	= { .len = FIELD_SIZEOF(struct iphdr, saddr) },
14634d74f8baSPatrick McHardy 	[IFLA_GRE_REMOTE]	= { .len = FIELD_SIZEOF(struct iphdr, daddr) },
1464c19e654dSHerbert Xu 	[IFLA_GRE_TTL]		= { .type = NLA_U8 },
1465c19e654dSHerbert Xu 	[IFLA_GRE_TOS]		= { .type = NLA_U8 },
1466c19e654dSHerbert Xu 	[IFLA_GRE_PMTUDISC]	= { .type = NLA_U8 },
14674565e991STom Herbert 	[IFLA_GRE_ENCAP_TYPE]	= { .type = NLA_U16 },
14684565e991STom Herbert 	[IFLA_GRE_ENCAP_FLAGS]	= { .type = NLA_U16 },
14694565e991STom Herbert 	[IFLA_GRE_ENCAP_SPORT]	= { .type = NLA_U16 },
14704565e991STom Herbert 	[IFLA_GRE_ENCAP_DPORT]	= { .type = NLA_U16 },
14712e15ea39SPravin B Shelar 	[IFLA_GRE_COLLECT_METADATA]	= { .type = NLA_FLAG },
147222a59be8SPhilip Prindeville 	[IFLA_GRE_IGNORE_DF]	= { .type = NLA_U8 },
14739830ad4cSCraig Gallek 	[IFLA_GRE_FWMARK]	= { .type = NLA_U32 },
147484e54fe0SWilliam Tu 	[IFLA_GRE_ERSPAN_INDEX]	= { .type = NLA_U32 },
1475f551c91dSWilliam Tu 	[IFLA_GRE_ERSPAN_VER]	= { .type = NLA_U8 },
1476f551c91dSWilliam Tu 	[IFLA_GRE_ERSPAN_DIR]	= { .type = NLA_U8 },
1477f551c91dSWilliam Tu 	[IFLA_GRE_ERSPAN_HWID]	= { .type = NLA_U16 },
1478c19e654dSHerbert Xu };
1479c19e654dSHerbert Xu 
1480c19e654dSHerbert Xu static struct rtnl_link_ops ipgre_link_ops __read_mostly = {
1481c19e654dSHerbert Xu 	.kind		= "gre",
1482c19e654dSHerbert Xu 	.maxtype	= IFLA_GRE_MAX,
1483c19e654dSHerbert Xu 	.policy		= ipgre_policy,
1484c19e654dSHerbert Xu 	.priv_size	= sizeof(struct ip_tunnel),
1485c19e654dSHerbert Xu 	.setup		= ipgre_tunnel_setup,
1486c19e654dSHerbert Xu 	.validate	= ipgre_tunnel_validate,
1487c19e654dSHerbert Xu 	.newlink	= ipgre_newlink,
1488c19e654dSHerbert Xu 	.changelink	= ipgre_changelink,
1489c5441932SPravin B Shelar 	.dellink	= ip_tunnel_dellink,
1490c19e654dSHerbert Xu 	.get_size	= ipgre_get_size,
1491c19e654dSHerbert Xu 	.fill_info	= ipgre_fill_info,
14921728d4faSNicolas Dichtel 	.get_link_net	= ip_tunnel_get_link_net,
1493c19e654dSHerbert Xu };
1494c19e654dSHerbert Xu 
1495e1a80002SHerbert Xu static struct rtnl_link_ops ipgre_tap_ops __read_mostly = {
1496e1a80002SHerbert Xu 	.kind		= "gretap",
1497e1a80002SHerbert Xu 	.maxtype	= IFLA_GRE_MAX,
1498e1a80002SHerbert Xu 	.policy		= ipgre_policy,
1499e1a80002SHerbert Xu 	.priv_size	= sizeof(struct ip_tunnel),
1500e1a80002SHerbert Xu 	.setup		= ipgre_tap_setup,
1501e1a80002SHerbert Xu 	.validate	= ipgre_tap_validate,
1502e1a80002SHerbert Xu 	.newlink	= ipgre_newlink,
1503e1a80002SHerbert Xu 	.changelink	= ipgre_changelink,
1504c5441932SPravin B Shelar 	.dellink	= ip_tunnel_dellink,
1505e1a80002SHerbert Xu 	.get_size	= ipgre_get_size,
1506e1a80002SHerbert Xu 	.fill_info	= ipgre_fill_info,
15071728d4faSNicolas Dichtel 	.get_link_net	= ip_tunnel_get_link_net,
1508e1a80002SHerbert Xu };
1509e1a80002SHerbert Xu 
151084e54fe0SWilliam Tu static struct rtnl_link_ops erspan_link_ops __read_mostly = {
151184e54fe0SWilliam Tu 	.kind		= "erspan",
151284e54fe0SWilliam Tu 	.maxtype	= IFLA_GRE_MAX,
151384e54fe0SWilliam Tu 	.policy		= ipgre_policy,
151484e54fe0SWilliam Tu 	.priv_size	= sizeof(struct ip_tunnel),
151584e54fe0SWilliam Tu 	.setup		= erspan_setup,
151684e54fe0SWilliam Tu 	.validate	= erspan_validate,
151784e54fe0SWilliam Tu 	.newlink	= ipgre_newlink,
151884e54fe0SWilliam Tu 	.changelink	= ipgre_changelink,
151984e54fe0SWilliam Tu 	.dellink	= ip_tunnel_dellink,
152084e54fe0SWilliam Tu 	.get_size	= ipgre_get_size,
152184e54fe0SWilliam Tu 	.fill_info	= ipgre_fill_info,
152284e54fe0SWilliam Tu 	.get_link_net	= ip_tunnel_get_link_net,
152384e54fe0SWilliam Tu };
152484e54fe0SWilliam Tu 
1525b2acd1dcSPravin B Shelar struct net_device *gretap_fb_dev_create(struct net *net, const char *name,
1526b2acd1dcSPravin B Shelar 					u8 name_assign_type)
1527b2acd1dcSPravin B Shelar {
1528b2acd1dcSPravin B Shelar 	struct nlattr *tb[IFLA_MAX + 1];
1529b2acd1dcSPravin B Shelar 	struct net_device *dev;
1530106da663SNicolas Dichtel 	LIST_HEAD(list_kill);
1531b2acd1dcSPravin B Shelar 	struct ip_tunnel *t;
1532b2acd1dcSPravin B Shelar 	int err;
1533b2acd1dcSPravin B Shelar 
1534b2acd1dcSPravin B Shelar 	memset(&tb, 0, sizeof(tb));
1535b2acd1dcSPravin B Shelar 
1536b2acd1dcSPravin B Shelar 	dev = rtnl_create_link(net, name, name_assign_type,
1537d0522f1cSDavid Ahern 			       &ipgre_tap_ops, tb, NULL);
1538b2acd1dcSPravin B Shelar 	if (IS_ERR(dev))
1539b2acd1dcSPravin B Shelar 		return dev;
1540b2acd1dcSPravin B Shelar 
1541b2acd1dcSPravin B Shelar 	/* Configure flow based GRE device. */
1542b2acd1dcSPravin B Shelar 	t = netdev_priv(dev);
1543b2acd1dcSPravin B Shelar 	t->collect_md = true;
1544b2acd1dcSPravin B Shelar 
15457a3f4a18SMatthias Schiffer 	err = ipgre_newlink(net, dev, tb, NULL, NULL);
1546106da663SNicolas Dichtel 	if (err < 0) {
1547106da663SNicolas Dichtel 		free_netdev(dev);
1548106da663SNicolas Dichtel 		return ERR_PTR(err);
1549106da663SNicolas Dichtel 	}
15507e059158SDavid Wragg 
15517e059158SDavid Wragg 	/* openvswitch users expect packet sizes to be unrestricted,
15527e059158SDavid Wragg 	 * so set the largest MTU we can.
15537e059158SDavid Wragg 	 */
15547e059158SDavid Wragg 	err = __ip_tunnel_change_mtu(dev, IP_MAX_MTU, false);
15557e059158SDavid Wragg 	if (err)
15567e059158SDavid Wragg 		goto out;
15577e059158SDavid Wragg 
1558da6f1da8SNicolas Dichtel 	err = rtnl_configure_link(dev, NULL);
1559da6f1da8SNicolas Dichtel 	if (err < 0)
1560da6f1da8SNicolas Dichtel 		goto out;
1561da6f1da8SNicolas Dichtel 
1562b2acd1dcSPravin B Shelar 	return dev;
1563b2acd1dcSPravin B Shelar out:
1564106da663SNicolas Dichtel 	ip_tunnel_dellink(dev, &list_kill);
1565106da663SNicolas Dichtel 	unregister_netdevice_many(&list_kill);
1566b2acd1dcSPravin B Shelar 	return ERR_PTR(err);
1567b2acd1dcSPravin B Shelar }
1568b2acd1dcSPravin B Shelar EXPORT_SYMBOL_GPL(gretap_fb_dev_create);
1569b2acd1dcSPravin B Shelar 
1570c5441932SPravin B Shelar static int __net_init ipgre_tap_init_net(struct net *net)
1571c5441932SPravin B Shelar {
15722e15ea39SPravin B Shelar 	return ip_tunnel_init_net(net, gre_tap_net_id, &ipgre_tap_ops, "gretap0");
1573c5441932SPravin B Shelar }
1574c5441932SPravin B Shelar 
157564bc1781SEric Dumazet static void __net_exit ipgre_tap_exit_batch_net(struct list_head *list_net)
1576c5441932SPravin B Shelar {
157764bc1781SEric Dumazet 	ip_tunnel_delete_nets(list_net, gre_tap_net_id, &ipgre_tap_ops);
1578c5441932SPravin B Shelar }
1579c5441932SPravin B Shelar 
1580c5441932SPravin B Shelar static struct pernet_operations ipgre_tap_net_ops = {
1581c5441932SPravin B Shelar 	.init = ipgre_tap_init_net,
158264bc1781SEric Dumazet 	.exit_batch = ipgre_tap_exit_batch_net,
1583c5441932SPravin B Shelar 	.id   = &gre_tap_net_id,
1584c5441932SPravin B Shelar 	.size = sizeof(struct ip_tunnel_net),
1585c5441932SPravin B Shelar };
15861da177e4SLinus Torvalds 
158784e54fe0SWilliam Tu static int __net_init erspan_init_net(struct net *net)
158884e54fe0SWilliam Tu {
158984e54fe0SWilliam Tu 	return ip_tunnel_init_net(net, erspan_net_id,
159084e54fe0SWilliam Tu 				  &erspan_link_ops, "erspan0");
159184e54fe0SWilliam Tu }
159284e54fe0SWilliam Tu 
159364bc1781SEric Dumazet static void __net_exit erspan_exit_batch_net(struct list_head *net_list)
159484e54fe0SWilliam Tu {
159564bc1781SEric Dumazet 	ip_tunnel_delete_nets(net_list, erspan_net_id, &erspan_link_ops);
159684e54fe0SWilliam Tu }
159784e54fe0SWilliam Tu 
159884e54fe0SWilliam Tu static struct pernet_operations erspan_net_ops = {
159984e54fe0SWilliam Tu 	.init = erspan_init_net,
160064bc1781SEric Dumazet 	.exit_batch = erspan_exit_batch_net,
160184e54fe0SWilliam Tu 	.id   = &erspan_net_id,
160284e54fe0SWilliam Tu 	.size = sizeof(struct ip_tunnel_net),
160384e54fe0SWilliam Tu };
160484e54fe0SWilliam Tu 
16051da177e4SLinus Torvalds static int __init ipgre_init(void)
16061da177e4SLinus Torvalds {
16071da177e4SLinus Torvalds 	int err;
16081da177e4SLinus Torvalds 
1609058bd4d2SJoe Perches 	pr_info("GRE over IPv4 tunneling driver\n");
16101da177e4SLinus Torvalds 
1611cfb8fbf2SEric W. Biederman 	err = register_pernet_device(&ipgre_net_ops);
161259a4c759SPavel Emelyanov 	if (err < 0)
1613c2892f02SAlexey Dobriyan 		return err;
1614c2892f02SAlexey Dobriyan 
1615c5441932SPravin B Shelar 	err = register_pernet_device(&ipgre_tap_net_ops);
1616c5441932SPravin B Shelar 	if (err < 0)
1617e3d0328cSWilliam Tu 		goto pnet_tap_failed;
1618c5441932SPravin B Shelar 
161984e54fe0SWilliam Tu 	err = register_pernet_device(&erspan_net_ops);
162084e54fe0SWilliam Tu 	if (err < 0)
162184e54fe0SWilliam Tu 		goto pnet_erspan_failed;
162284e54fe0SWilliam Tu 
16239f57c67cSPravin B Shelar 	err = gre_add_protocol(&ipgre_protocol, GREPROTO_CISCO);
1624c2892f02SAlexey Dobriyan 	if (err < 0) {
1625058bd4d2SJoe Perches 		pr_info("%s: can't add protocol\n", __func__);
1626c2892f02SAlexey Dobriyan 		goto add_proto_failed;
1627c2892f02SAlexey Dobriyan 	}
16287daa0004SPavel Emelyanov 
1629c19e654dSHerbert Xu 	err = rtnl_link_register(&ipgre_link_ops);
1630c19e654dSHerbert Xu 	if (err < 0)
1631c19e654dSHerbert Xu 		goto rtnl_link_failed;
1632c19e654dSHerbert Xu 
1633e1a80002SHerbert Xu 	err = rtnl_link_register(&ipgre_tap_ops);
1634e1a80002SHerbert Xu 	if (err < 0)
1635e1a80002SHerbert Xu 		goto tap_ops_failed;
1636e1a80002SHerbert Xu 
163784e54fe0SWilliam Tu 	err = rtnl_link_register(&erspan_link_ops);
163884e54fe0SWilliam Tu 	if (err < 0)
163984e54fe0SWilliam Tu 		goto erspan_link_failed;
164084e54fe0SWilliam Tu 
1641c5441932SPravin B Shelar 	return 0;
1642c19e654dSHerbert Xu 
164384e54fe0SWilliam Tu erspan_link_failed:
164484e54fe0SWilliam Tu 	rtnl_link_unregister(&ipgre_tap_ops);
1645e1a80002SHerbert Xu tap_ops_failed:
1646e1a80002SHerbert Xu 	rtnl_link_unregister(&ipgre_link_ops);
1647c19e654dSHerbert Xu rtnl_link_failed:
16489f57c67cSPravin B Shelar 	gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO);
1649c2892f02SAlexey Dobriyan add_proto_failed:
165084e54fe0SWilliam Tu 	unregister_pernet_device(&erspan_net_ops);
165184e54fe0SWilliam Tu pnet_erspan_failed:
1652c5441932SPravin B Shelar 	unregister_pernet_device(&ipgre_tap_net_ops);
1653e3d0328cSWilliam Tu pnet_tap_failed:
1654c2892f02SAlexey Dobriyan 	unregister_pernet_device(&ipgre_net_ops);
1655c5441932SPravin B Shelar 	return err;
16561da177e4SLinus Torvalds }
16571da177e4SLinus Torvalds 
1658db44575fSAlexey Kuznetsov static void __exit ipgre_fini(void)
16591da177e4SLinus Torvalds {
1660e1a80002SHerbert Xu 	rtnl_link_unregister(&ipgre_tap_ops);
1661c19e654dSHerbert Xu 	rtnl_link_unregister(&ipgre_link_ops);
166284e54fe0SWilliam Tu 	rtnl_link_unregister(&erspan_link_ops);
16639f57c67cSPravin B Shelar 	gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO);
1664c5441932SPravin B Shelar 	unregister_pernet_device(&ipgre_tap_net_ops);
1665c2892f02SAlexey Dobriyan 	unregister_pernet_device(&ipgre_net_ops);
166684e54fe0SWilliam Tu 	unregister_pernet_device(&erspan_net_ops);
16671da177e4SLinus Torvalds }
16681da177e4SLinus Torvalds 
16691da177e4SLinus Torvalds module_init(ipgre_init);
16701da177e4SLinus Torvalds module_exit(ipgre_fini);
16711da177e4SLinus Torvalds MODULE_LICENSE("GPL");
16724d74f8baSPatrick McHardy MODULE_ALIAS_RTNL_LINK("gre");
16734d74f8baSPatrick McHardy MODULE_ALIAS_RTNL_LINK("gretap");
167484e54fe0SWilliam Tu MODULE_ALIAS_RTNL_LINK("erspan");
16758909c9adSVasiliy Kulikov MODULE_ALIAS_NETDEV("gre0");
1676c5441932SPravin B Shelar MODULE_ALIAS_NETDEV("gretap0");
167784e54fe0SWilliam Tu MODULE_ALIAS_NETDEV("erspan0");
1678