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;
110aab1e898SGuillaume Nault static const struct header_ops ipgre_header_ops;
111aab1e898SGuillaume Nault
1121da177e4SLinus Torvalds static int ipgre_tunnel_init(struct net_device *dev);
1131a66a836SWilliam Tu static void erspan_build_header(struct sk_buff *skb,
114c69de58bSWilliam Tu u32 id, u32 index,
115a3222dc9SWilliam Tu bool truncate, bool is_ipv4);
116eb8ce741SPavel Emelyanov
117c7d03a00SAlexey Dobriyan static unsigned int ipgre_net_id __read_mostly;
118c7d03a00SAlexey Dobriyan static unsigned int gre_tap_net_id __read_mostly;
11984e54fe0SWilliam Tu static unsigned int erspan_net_id __read_mostly;
120eb8ce741SPavel Emelyanov
ipgre_err(struct sk_buff * skb,u32 info,const struct tnl_ptk_info * tpi)12132bbd879SStefano Brivio static int ipgre_err(struct sk_buff *skb, u32 info,
122bda7bb46SPravin B Shelar const struct tnl_ptk_info *tpi)
1231da177e4SLinus Torvalds {
1241da177e4SLinus Torvalds
125071f92d0SRami Rosen /* All the routers (except for Linux) return only
1261da177e4SLinus Torvalds 8 bytes of packet payload. It means, that precise relaying of
1271da177e4SLinus Torvalds ICMP in the real Internet is absolutely infeasible.
1281da177e4SLinus Torvalds
1291da177e4SLinus Torvalds Moreover, Cisco "wise men" put GRE key to the third word
130c5441932SPravin B Shelar in GRE header. It makes impossible maintaining even soft
131c5441932SPravin B Shelar state for keyed GRE tunnels with enabled checksum. Tell
132c5441932SPravin B Shelar them "thank you".
1331da177e4SLinus Torvalds
1341da177e4SLinus Torvalds Well, I wonder, rfc1812 was written by Cisco employee,
135bff52857Sstephen hemminger what the hell these idiots break standards established
136bff52857Sstephen hemminger by themselves???
1371da177e4SLinus Torvalds */
138c5441932SPravin B Shelar struct net *net = dev_net(skb->dev);
139c5441932SPravin B Shelar struct ip_tunnel_net *itn;
14096f5a846SEric Dumazet const struct iphdr *iph;
14188c7664fSArnaldo Carvalho de Melo const int type = icmp_hdr(skb)->type;
14288c7664fSArnaldo Carvalho de Melo const int code = icmp_hdr(skb)->code;
14320e1954fSEric Dumazet unsigned int data_len = 0;
1441da177e4SLinus Torvalds struct ip_tunnel *t;
145d2083287Sstephen hemminger
146bda7bb46SPravin B Shelar if (tpi->proto == htons(ETH_P_TEB))
147c5441932SPravin B Shelar itn = net_generic(net, gre_tap_net_id);
14851dc63e3SHaishuang Yan else if (tpi->proto == htons(ETH_P_ERSPAN) ||
14951dc63e3SHaishuang Yan tpi->proto == htons(ETH_P_ERSPAN2))
15051dc63e3SHaishuang Yan itn = net_generic(net, erspan_net_id);
151c5441932SPravin B Shelar else
152c5441932SPravin B Shelar itn = net_generic(net, ipgre_net_id);
153c5441932SPravin B Shelar
154c0c0c50fSDuan Jiong iph = (const struct iphdr *)(icmp_hdr(skb) + 1);
155bda7bb46SPravin B Shelar t = ip_tunnel_lookup(itn, skb->dev->ifindex, tpi->flags,
156bda7bb46SPravin B Shelar iph->daddr, iph->saddr, tpi->key);
157d2083287Sstephen hemminger
15851456b29SIan Morris if (!t)
15932bbd879SStefano Brivio return -ENOENT;
16032bbd879SStefano Brivio
16132bbd879SStefano Brivio switch (type) {
16232bbd879SStefano Brivio default:
16332bbd879SStefano Brivio case ICMP_PARAMETERPROB:
16432bbd879SStefano Brivio return 0;
16532bbd879SStefano Brivio
16632bbd879SStefano Brivio case ICMP_DEST_UNREACH:
16732bbd879SStefano Brivio switch (code) {
16832bbd879SStefano Brivio case ICMP_SR_FAILED:
16932bbd879SStefano Brivio case ICMP_PORT_UNREACH:
17032bbd879SStefano Brivio /* Impossible event. */
17132bbd879SStefano Brivio return 0;
17232bbd879SStefano Brivio default:
17332bbd879SStefano Brivio /* All others are translated to HOST_UNREACH.
17432bbd879SStefano Brivio rfc2003 contains "deep thoughts" about NET_UNREACH,
17532bbd879SStefano Brivio I believe they are just ether pollution. --ANK
17632bbd879SStefano Brivio */
17732bbd879SStefano Brivio break;
17832bbd879SStefano Brivio }
17932bbd879SStefano Brivio break;
18032bbd879SStefano Brivio
18132bbd879SStefano Brivio case ICMP_TIME_EXCEEDED:
18232bbd879SStefano Brivio if (code != ICMP_EXC_TTL)
18332bbd879SStefano Brivio return 0;
18432bbd879SStefano Brivio data_len = icmp_hdr(skb)->un.reserved[1] * 4; /* RFC 4884 4.1 */
18532bbd879SStefano Brivio break;
18632bbd879SStefano Brivio
18732bbd879SStefano Brivio case ICMP_REDIRECT:
18832bbd879SStefano Brivio break;
18932bbd879SStefano Brivio }
19036393395SDavid S. Miller
1919b8c6d7bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6)
1929b8c6d7bSEric Dumazet if (tpi->proto == htons(ETH_P_IPV6) &&
19320e1954fSEric Dumazet !ip6_err_gen_icmpv6_unreach(skb, iph->ihl * 4 + tpi->hdr_len,
19420e1954fSEric Dumazet type, data_len))
19532bbd879SStefano Brivio return 0;
1969b8c6d7bSEric Dumazet #endif
1979b8c6d7bSEric Dumazet
19836393395SDavid S. Miller if (t->parms.iph.daddr == 0 ||
199f97c1e0cSJoe Perches ipv4_is_multicast(t->parms.iph.daddr))
20032bbd879SStefano Brivio return 0;
2011da177e4SLinus Torvalds
2021da177e4SLinus Torvalds if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED)
20332bbd879SStefano Brivio return 0;
2041da177e4SLinus Torvalds
205da6185d8SWei Yongjun if (time_before(jiffies, t->err_time + IPTUNNEL_ERR_TIMEO))
2061da177e4SLinus Torvalds t->err_count++;
2071da177e4SLinus Torvalds else
2081da177e4SLinus Torvalds t->err_count = 1;
2091da177e4SLinus Torvalds t->err_time = jiffies;
21032bbd879SStefano Brivio
21132bbd879SStefano Brivio return 0;
2129f57c67cSPravin B Shelar }
2139f57c67cSPravin B Shelar
gre_err(struct sk_buff * skb,u32 info)2149f57c67cSPravin B Shelar static void gre_err(struct sk_buff *skb, u32 info)
2159f57c67cSPravin B Shelar {
2169f57c67cSPravin B Shelar /* All the routers (except for Linux) return only
2179f57c67cSPravin B Shelar * 8 bytes of packet payload. It means, that precise relaying of
2189f57c67cSPravin B Shelar * ICMP in the real Internet is absolutely infeasible.
2199f57c67cSPravin B Shelar *
2209f57c67cSPravin B Shelar * Moreover, Cisco "wise men" put GRE key to the third word
2219f57c67cSPravin B Shelar * in GRE header. It makes impossible maintaining even soft
2229f57c67cSPravin B Shelar * state for keyed
2239f57c67cSPravin B Shelar * GRE tunnels with enabled checksum. Tell them "thank you".
2249f57c67cSPravin B Shelar *
2259f57c67cSPravin B Shelar * Well, I wonder, rfc1812 was written by Cisco employee,
2269f57c67cSPravin B Shelar * what the hell these idiots break standards established
2279f57c67cSPravin B Shelar * by themselves???
2289f57c67cSPravin B Shelar */
2299f57c67cSPravin B Shelar
230e582615aSEric Dumazet const struct iphdr *iph = (struct iphdr *)skb->data;
2319f57c67cSPravin B Shelar const int type = icmp_hdr(skb)->type;
2329f57c67cSPravin B Shelar const int code = icmp_hdr(skb)->code;
2339f57c67cSPravin B Shelar struct tnl_ptk_info tpi;
2349f57c67cSPravin B Shelar
235b0350d51SHaishuang Yan if (gre_parse_header(skb, &tpi, NULL, htons(ETH_P_IP),
236b0350d51SHaishuang Yan iph->ihl * 4) < 0)
2379f57c67cSPravin B Shelar return;
2389f57c67cSPravin B Shelar
2399f57c67cSPravin B Shelar if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) {
2409f57c67cSPravin B Shelar ipv4_update_pmtu(skb, dev_net(skb->dev), info,
241d888f396SMaciej Żenczykowski skb->dev->ifindex, IPPROTO_GRE);
2429f57c67cSPravin B Shelar return;
2439f57c67cSPravin B Shelar }
2449f57c67cSPravin B Shelar if (type == ICMP_REDIRECT) {
2451042caa7SMaciej Żenczykowski ipv4_redirect(skb, dev_net(skb->dev), skb->dev->ifindex,
2461042caa7SMaciej Żenczykowski IPPROTO_GRE);
2479f57c67cSPravin B Shelar return;
2489f57c67cSPravin B Shelar }
2499f57c67cSPravin B Shelar
2509f57c67cSPravin B Shelar ipgre_err(skb, info, &tpi);
2511da177e4SLinus Torvalds }
2521da177e4SLinus Torvalds
is_erspan_type1(int gre_hdr_len)253f989d546SWilliam Tu static bool is_erspan_type1(int gre_hdr_len)
254f989d546SWilliam Tu {
255f989d546SWilliam Tu /* Both ERSPAN type I (version 0) and type II (version 1) use
256f989d546SWilliam Tu * protocol 0x88BE, but the type I has only 4-byte GRE header,
257f989d546SWilliam Tu * while type II has 8-byte.
258f989d546SWilliam Tu */
259f989d546SWilliam Tu return gre_hdr_len == 4;
260f989d546SWilliam Tu }
261f989d546SWilliam Tu
erspan_rcv(struct sk_buff * skb,struct tnl_ptk_info * tpi,int gre_hdr_len)26284e54fe0SWilliam Tu static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi,
26384e54fe0SWilliam Tu int gre_hdr_len)
26484e54fe0SWilliam Tu {
26584e54fe0SWilliam Tu struct net *net = dev_net(skb->dev);
26684e54fe0SWilliam Tu struct metadata_dst *tun_dst = NULL;
2671d7e2ed2SWilliam Tu struct erspan_base_hdr *ershdr;
26884e54fe0SWilliam Tu struct ip_tunnel_net *itn;
26984e54fe0SWilliam Tu struct ip_tunnel *tunnel;
27084e54fe0SWilliam Tu const struct iphdr *iph;
2713df19283SWilliam Tu struct erspan_md2 *md2;
2721d7e2ed2SWilliam Tu int ver;
27384e54fe0SWilliam Tu int len;
27484e54fe0SWilliam Tu
27584e54fe0SWilliam Tu itn = net_generic(net, erspan_net_id);
27684e54fe0SWilliam Tu iph = ip_hdr(skb);
277f989d546SWilliam Tu if (is_erspan_type1(gre_hdr_len)) {
278f989d546SWilliam Tu ver = 0;
279f989d546SWilliam Tu tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex,
280f989d546SWilliam Tu tpi->flags | TUNNEL_NO_KEY,
281f989d546SWilliam Tu iph->saddr, iph->daddr, 0);
282f989d546SWilliam Tu } else {
2834e3fdeecSEric Dumazet if (unlikely(!pskb_may_pull(skb,
2844e3fdeecSEric Dumazet gre_hdr_len + sizeof(*ershdr))))
2854e3fdeecSEric Dumazet return PACKET_REJECT;
2864e3fdeecSEric Dumazet
2871d7e2ed2SWilliam Tu ershdr = (struct erspan_base_hdr *)(skb->data + gre_hdr_len);
288c69de58bSWilliam Tu ver = ershdr->ver;
2894e3fdeecSEric Dumazet iph = ip_hdr(skb);
29084e54fe0SWilliam Tu tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex,
29184e54fe0SWilliam Tu tpi->flags | TUNNEL_KEY,
29284e54fe0SWilliam Tu iph->saddr, iph->daddr, tpi->key);
293f989d546SWilliam Tu }
29484e54fe0SWilliam Tu
29584e54fe0SWilliam Tu if (tunnel) {
296f989d546SWilliam Tu if (is_erspan_type1(gre_hdr_len))
297f989d546SWilliam Tu len = gre_hdr_len;
298f989d546SWilliam Tu else
2991d7e2ed2SWilliam Tu len = gre_hdr_len + erspan_hdr_len(ver);
300f989d546SWilliam Tu
3011d7e2ed2SWilliam Tu if (unlikely(!pskb_may_pull(skb, len)))
302ae3e1337SWilliam Tu return PACKET_REJECT;
3031d7e2ed2SWilliam Tu
30484e54fe0SWilliam Tu if (__iptunnel_pull_header(skb,
3051d7e2ed2SWilliam Tu len,
30684e54fe0SWilliam Tu htons(ETH_P_TEB),
30784e54fe0SWilliam Tu false, false) < 0)
30884e54fe0SWilliam Tu goto drop;
30984e54fe0SWilliam Tu
3101a66a836SWilliam Tu if (tunnel->collect_md) {
311492b67e2SLorenzo Bianconi struct erspan_metadata *pkt_md, *md;
3121a66a836SWilliam Tu struct ip_tunnel_info *info;
313492b67e2SLorenzo Bianconi unsigned char *gh;
3141a66a836SWilliam Tu __be64 tun_id;
3151a66a836SWilliam Tu __be16 flags;
3161a66a836SWilliam Tu
3171a66a836SWilliam Tu tpi->flags |= TUNNEL_KEY;
3181a66a836SWilliam Tu flags = tpi->flags;
3191a66a836SWilliam Tu tun_id = key32_to_tunnel_id(tpi->key);
3201a66a836SWilliam Tu
3211a66a836SWilliam Tu tun_dst = ip_tun_rx_dst(skb, flags,
3221a66a836SWilliam Tu tun_id, sizeof(*md));
3231a66a836SWilliam Tu if (!tun_dst)
3241a66a836SWilliam Tu return PACKET_REJECT;
3251a66a836SWilliam Tu
326492b67e2SLorenzo Bianconi /* skb can be uncloned in __iptunnel_pull_header, so
327492b67e2SLorenzo Bianconi * old pkt_md is no longer valid and we need to reset
328492b67e2SLorenzo Bianconi * it
329492b67e2SLorenzo Bianconi */
330492b67e2SLorenzo Bianconi gh = skb_network_header(skb) +
331492b67e2SLorenzo Bianconi skb_network_header_len(skb);
332492b67e2SLorenzo Bianconi pkt_md = (struct erspan_metadata *)(gh + gre_hdr_len +
333492b67e2SLorenzo Bianconi sizeof(*ershdr));
3341a66a836SWilliam Tu md = ip_tunnel_info_opts(&tun_dst->u.tun_info);
335f551c91dSWilliam Tu md->version = ver;
3363df19283SWilliam Tu md2 = &md->u.md2;
3373df19283SWilliam Tu memcpy(md2, pkt_md, ver == 1 ? ERSPAN_V1_MDSIZE :
3383df19283SWilliam Tu ERSPAN_V2_MDSIZE);
339f551c91dSWilliam Tu
3401a66a836SWilliam Tu info = &tun_dst->u.tun_info;
3411a66a836SWilliam Tu info->key.tun_flags |= TUNNEL_ERSPAN_OPT;
3421a66a836SWilliam Tu info->options_len = sizeof(*md);
3431a66a836SWilliam Tu }
3441a66a836SWilliam Tu
34584e54fe0SWilliam Tu skb_reset_mac_header(skb);
34684e54fe0SWilliam Tu ip_tunnel_rcv(tunnel, skb, tpi, tun_dst, log_ecn_error);
34784e54fe0SWilliam Tu return PACKET_RCVD;
34884e54fe0SWilliam Tu }
3495a64506bSHaishuang Yan return PACKET_REJECT;
3505a64506bSHaishuang Yan
35184e54fe0SWilliam Tu drop:
35284e54fe0SWilliam Tu kfree_skb(skb);
35384e54fe0SWilliam Tu return PACKET_RCVD;
35484e54fe0SWilliam Tu }
35584e54fe0SWilliam Tu
__ipgre_rcv(struct sk_buff * skb,const struct tnl_ptk_info * tpi,struct ip_tunnel_net * itn,int hdr_len,bool raw_proto)356125372faSJiri Benc static int __ipgre_rcv(struct sk_buff *skb, const struct tnl_ptk_info *tpi,
357125372faSJiri Benc struct ip_tunnel_net *itn, int hdr_len, bool raw_proto)
3581da177e4SLinus Torvalds {
3592e15ea39SPravin B Shelar struct metadata_dst *tun_dst = NULL;
360b71d1d42SEric Dumazet const struct iphdr *iph;
3611da177e4SLinus Torvalds struct ip_tunnel *tunnel;
3621da177e4SLinus Torvalds
363eddc9ec5SArnaldo Carvalho de Melo iph = ip_hdr(skb);
364bda7bb46SPravin B Shelar tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, tpi->flags,
365bda7bb46SPravin B Shelar iph->saddr, iph->daddr, tpi->key);
3661da177e4SLinus Torvalds
367d2083287Sstephen hemminger if (tunnel) {
368c0d59da7Swenxu const struct iphdr *tnl_params;
369c0d59da7Swenxu
370125372faSJiri Benc if (__iptunnel_pull_header(skb, hdr_len, tpi->proto,
371125372faSJiri Benc raw_proto, false) < 0)
372244a797bSJiri Benc goto drop;
373244a797bSJiri Benc
374aab1e898SGuillaume Nault /* Special case for ipgre_header_parse(), which expects the
375aab1e898SGuillaume Nault * mac_header to point to the outer IP header.
376aab1e898SGuillaume Nault */
377aab1e898SGuillaume Nault if (tunnel->dev->header_ops == &ipgre_header_ops)
3780e3da5bbSTimo Teräs skb_pop_mac_header(skb);
379e271c7b4SJiri Benc else
380e271c7b4SJiri Benc skb_reset_mac_header(skb);
381c0d59da7Swenxu
382c0d59da7Swenxu tnl_params = &tunnel->parms.iph;
383c0d59da7Swenxu if (tunnel->collect_md || tnl_params->daddr == 0) {
384c29a70d2SPravin B Shelar __be16 flags;
385c29a70d2SPravin B Shelar __be64 tun_id;
3862e15ea39SPravin B Shelar
387c29a70d2SPravin B Shelar flags = tpi->flags & (TUNNEL_CSUM | TUNNEL_KEY);
388d817f432SAmir Vadai tun_id = key32_to_tunnel_id(tpi->key);
389c29a70d2SPravin B Shelar tun_dst = ip_tun_rx_dst(skb, flags, tun_id, 0);
3902e15ea39SPravin B Shelar if (!tun_dst)
3912e15ea39SPravin B Shelar return PACKET_REJECT;
3922e15ea39SPravin B Shelar }
3932e15ea39SPravin B Shelar
3942e15ea39SPravin B Shelar ip_tunnel_rcv(tunnel, skb, tpi, tun_dst, log_ecn_error);
395bda7bb46SPravin B Shelar return PACKET_RCVD;
3961da177e4SLinus Torvalds }
397125372faSJiri Benc return PACKET_NEXT;
398244a797bSJiri Benc
399244a797bSJiri Benc drop:
400244a797bSJiri Benc kfree_skb(skb);
401244a797bSJiri Benc return PACKET_RCVD;
4021da177e4SLinus Torvalds }
4031da177e4SLinus Torvalds
ipgre_rcv(struct sk_buff * skb,const struct tnl_ptk_info * tpi,int hdr_len)404125372faSJiri Benc static int ipgre_rcv(struct sk_buff *skb, const struct tnl_ptk_info *tpi,
405125372faSJiri Benc int hdr_len)
406125372faSJiri Benc {
407125372faSJiri Benc struct net *net = dev_net(skb->dev);
408125372faSJiri Benc struct ip_tunnel_net *itn;
409125372faSJiri Benc int res;
410125372faSJiri Benc
411125372faSJiri Benc if (tpi->proto == htons(ETH_P_TEB))
412125372faSJiri Benc itn = net_generic(net, gre_tap_net_id);
413125372faSJiri Benc else
414125372faSJiri Benc itn = net_generic(net, ipgre_net_id);
415125372faSJiri Benc
416125372faSJiri Benc res = __ipgre_rcv(skb, tpi, itn, hdr_len, false);
417125372faSJiri Benc if (res == PACKET_NEXT && tpi->proto == htons(ETH_P_TEB)) {
418125372faSJiri Benc /* ipgre tunnels in collect metadata mode should receive
419125372faSJiri Benc * also ETH_P_TEB traffic.
420125372faSJiri Benc */
421125372faSJiri Benc itn = net_generic(net, ipgre_net_id);
422125372faSJiri Benc res = __ipgre_rcv(skb, tpi, itn, hdr_len, true);
423125372faSJiri Benc }
424125372faSJiri Benc return res;
425125372faSJiri Benc }
426125372faSJiri Benc
gre_rcv(struct sk_buff * skb)4279f57c67cSPravin B Shelar static int gre_rcv(struct sk_buff *skb)
4289f57c67cSPravin B Shelar {
4299f57c67cSPravin B Shelar struct tnl_ptk_info tpi;
4309f57c67cSPravin B Shelar bool csum_err = false;
43195f5c64cSTom Herbert int hdr_len;
4329f57c67cSPravin B Shelar
4339f57c67cSPravin B Shelar #ifdef CONFIG_NET_IPGRE_BROADCAST
4349f57c67cSPravin B Shelar if (ipv4_is_multicast(ip_hdr(skb)->daddr)) {
4359f57c67cSPravin B Shelar /* Looped back packet, drop it! */
4369f57c67cSPravin B Shelar if (rt_is_output_route(skb_rtable(skb)))
4379f57c67cSPravin B Shelar goto drop;
4389f57c67cSPravin B Shelar }
4399f57c67cSPravin B Shelar #endif
4409f57c67cSPravin B Shelar
441e582615aSEric Dumazet hdr_len = gre_parse_header(skb, &tpi, &csum_err, htons(ETH_P_IP), 0);
442f132ae7cSJiri Benc if (hdr_len < 0)
44395f5c64cSTom Herbert goto drop;
44495f5c64cSTom Herbert
445f551c91dSWilliam Tu if (unlikely(tpi.proto == htons(ETH_P_ERSPAN) ||
446f551c91dSWilliam Tu tpi.proto == htons(ETH_P_ERSPAN2))) {
44784e54fe0SWilliam Tu if (erspan_rcv(skb, &tpi, hdr_len) == PACKET_RCVD)
44884e54fe0SWilliam Tu return 0;
449dd8d5b8cSHaishuang Yan goto out;
45084e54fe0SWilliam Tu }
45184e54fe0SWilliam Tu
452244a797bSJiri Benc if (ipgre_rcv(skb, &tpi, hdr_len) == PACKET_RCVD)
4539f57c67cSPravin B Shelar return 0;
4549f57c67cSPravin B Shelar
455dd8d5b8cSHaishuang Yan out:
4569f57c67cSPravin B Shelar icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
4579f57c67cSPravin B Shelar drop:
4589f57c67cSPravin B Shelar kfree_skb(skb);
4599f57c67cSPravin B Shelar return 0;
4609f57c67cSPravin B Shelar }
4619f57c67cSPravin B Shelar
__gre_xmit(struct sk_buff * skb,struct net_device * dev,const struct iphdr * tnl_params,__be16 proto)462c5441932SPravin B Shelar static void __gre_xmit(struct sk_buff *skb, struct net_device *dev,
463c5441932SPravin B Shelar const struct iphdr *tnl_params,
464c5441932SPravin B Shelar __be16 proto)
465c5441932SPravin B Shelar {
466c5441932SPravin B Shelar struct ip_tunnel *tunnel = netdev_priv(dev);
467ff827bebSPeilin Ye __be16 flags = tunnel->parms.o_flags;
468cef401deSEric Dumazet
469c5441932SPravin B Shelar /* Push GRE header. */
470182a352dSTom Herbert gre_build_header(skb, tunnel->tun_hlen,
471ff827bebSPeilin Ye flags, proto, tunnel->parms.o_key,
47231c417c9SPeilin Ye (flags & TUNNEL_SEQ) ? htonl(atomic_fetch_inc(&tunnel->o_seqno)) : 0);
4731da177e4SLinus Torvalds
474bf3d6a8fSNicolas Dichtel ip_tunnel_xmit(skb, dev, tnl_params, tnl_params->protocol);
4751da177e4SLinus Torvalds }
4761da177e4SLinus Torvalds
gre_handle_offloads(struct sk_buff * skb,bool csum)477aed069dfSAlexander Duyck static int gre_handle_offloads(struct sk_buff *skb, bool csum)
478b2acd1dcSPravin B Shelar {
4796fa79666SEdward Cree return iptunnel_handle_offloads(skb, csum ? SKB_GSO_GRE_CSUM : SKB_GSO_GRE);
480b2acd1dcSPravin B Shelar }
481b2acd1dcSPravin B Shelar
gre_fb_xmit(struct sk_buff * skb,struct net_device * dev,__be16 proto)482862a03c3SWilliam Tu static void gre_fb_xmit(struct sk_buff *skb, struct net_device *dev,
483862a03c3SWilliam Tu __be16 proto)
484862a03c3SWilliam Tu {
48577a5196aSWilliam Tu struct ip_tunnel *tunnel = netdev_priv(dev);
486862a03c3SWilliam Tu struct ip_tunnel_info *tun_info;
487862a03c3SWilliam Tu const struct ip_tunnel_key *key;
488862a03c3SWilliam Tu int tunnel_hlen;
489962924faSwenxu __be16 flags;
490862a03c3SWilliam Tu
491862a03c3SWilliam Tu tun_info = skb_tunnel_info(skb);
492862a03c3SWilliam Tu if (unlikely(!tun_info || !(tun_info->mode & IP_TUNNEL_INFO_TX) ||
493862a03c3SWilliam Tu ip_tunnel_info_af(tun_info) != AF_INET))
494862a03c3SWilliam Tu goto err_free_skb;
495862a03c3SWilliam Tu
496862a03c3SWilliam Tu key = &tun_info->key;
497862a03c3SWilliam Tu tunnel_hlen = gre_calc_hlen(key->tun_flags);
498862a03c3SWilliam Tu
499962924faSwenxu if (skb_cow_head(skb, dev->needed_headroom))
500962924faSwenxu goto err_free_skb;
5012e15ea39SPravin B Shelar
5022e15ea39SPravin B Shelar /* Push Tunnel header. */
503aed069dfSAlexander Duyck if (gre_handle_offloads(skb, !!(tun_info->key.tun_flags & TUNNEL_CSUM)))
504962924faSwenxu goto err_free_skb;
5052e15ea39SPravin B Shelar
50677a5196aSWilliam Tu flags = tun_info->key.tun_flags &
50777a5196aSWilliam Tu (TUNNEL_CSUM | TUNNEL_KEY | TUNNEL_SEQ);
508cba65321SDavid S. Miller gre_build_header(skb, tunnel_hlen, flags, proto,
50977a5196aSWilliam Tu tunnel_id_to_key32(tun_info->key.tun_id),
51031c417c9SPeilin Ye (flags & TUNNEL_SEQ) ? htonl(atomic_fetch_inc(&tunnel->o_seqno)) : 0);
5112e15ea39SPravin B Shelar
512962924faSwenxu ip_md_tunnel_xmit(skb, dev, IPPROTO_GRE, tunnel_hlen);
513039f5062SPravin B Shelar
5142e15ea39SPravin B Shelar return;
5152e15ea39SPravin B Shelar
5162e15ea39SPravin B Shelar err_free_skb:
5172e15ea39SPravin B Shelar kfree_skb(skb);
518c4794d22SEric Dumazet DEV_STATS_INC(dev, tx_dropped);
5192e15ea39SPravin B Shelar }
5202e15ea39SPravin B Shelar
erspan_fb_xmit(struct sk_buff * skb,struct net_device * dev)52120704bd1SXin Long static void erspan_fb_xmit(struct sk_buff *skb, struct net_device *dev)
5221a66a836SWilliam Tu {
5231a66a836SWilliam Tu struct ip_tunnel *tunnel = netdev_priv(dev);
5241a66a836SWilliam Tu struct ip_tunnel_info *tun_info;
5251a66a836SWilliam Tu const struct ip_tunnel_key *key;
5261a66a836SWilliam Tu struct erspan_metadata *md;
5271a66a836SWilliam Tu bool truncate = false;
528962924faSwenxu __be16 proto;
5291a66a836SWilliam Tu int tunnel_hlen;
530f551c91dSWilliam Tu int version;
5311baf5ebfSWilliam Tu int nhoff;
5321a66a836SWilliam Tu
5331a66a836SWilliam Tu tun_info = skb_tunnel_info(skb);
5341a66a836SWilliam Tu if (unlikely(!tun_info || !(tun_info->mode & IP_TUNNEL_INFO_TX) ||
5351a66a836SWilliam Tu ip_tunnel_info_af(tun_info) != AF_INET))
5361a66a836SWilliam Tu goto err_free_skb;
5371a66a836SWilliam Tu
5381a66a836SWilliam Tu key = &tun_info->key;
539256c87c1SPieter Jansen van Vuuren if (!(tun_info->key.tun_flags & TUNNEL_ERSPAN_OPT))
540962924faSwenxu goto err_free_skb;
5412eb8d6d2SXin Long if (tun_info->options_len < sizeof(*md))
542962924faSwenxu goto err_free_skb;
5432eb8d6d2SXin Long md = ip_tunnel_info_opts(tun_info);
5441a66a836SWilliam Tu
5451a66a836SWilliam Tu /* ERSPAN has fixed 8 byte GRE header */
546f551c91dSWilliam Tu version = md->version;
547f551c91dSWilliam Tu tunnel_hlen = 8 + erspan_hdr_len(version);
5481a66a836SWilliam Tu
549962924faSwenxu if (skb_cow_head(skb, dev->needed_headroom))
550962924faSwenxu goto err_free_skb;
5511a66a836SWilliam Tu
5521a66a836SWilliam Tu if (gre_handle_offloads(skb, false))
553962924faSwenxu goto err_free_skb;
5541a66a836SWilliam Tu
555f192970dSWilliam Tu if (skb->len > dev->mtu + dev->hard_header_len) {
55602d84f3eSYuanjun Gong if (pskb_trim(skb, dev->mtu + dev->hard_header_len))
55702d84f3eSYuanjun Gong goto err_free_skb;
5581a66a836SWilliam Tu truncate = true;
5591a66a836SWilliam Tu }
5601a66a836SWilliam Tu
5618e50ed77SEric Dumazet nhoff = skb_network_offset(skb);
5621baf5ebfSWilliam Tu if (skb->protocol == htons(ETH_P_IP) &&
5631baf5ebfSWilliam Tu (ntohs(ip_hdr(skb)->tot_len) > skb->len - nhoff))
5641baf5ebfSWilliam Tu truncate = true;
5651baf5ebfSWilliam Tu
566301bd140SEric Dumazet if (skb->protocol == htons(ETH_P_IPV6)) {
567301bd140SEric Dumazet int thoff;
568301bd140SEric Dumazet
569301bd140SEric Dumazet if (skb_transport_header_was_set(skb))
5708e50ed77SEric Dumazet thoff = skb_transport_offset(skb);
571301bd140SEric Dumazet else
572301bd140SEric Dumazet thoff = nhoff + sizeof(struct ipv6hdr);
573301bd140SEric Dumazet if (ntohs(ipv6_hdr(skb)->payload_len) > skb->len - thoff)
574d5db21a3SWilliam Tu truncate = true;
575301bd140SEric Dumazet }
576d5db21a3SWilliam Tu
577f551c91dSWilliam Tu if (version == 1) {
578c69de58bSWilliam Tu erspan_build_header(skb, ntohl(tunnel_id_to_key32(key->tun_id)),
5791d7e2ed2SWilliam Tu ntohl(md->u.index), truncate, true);
58020704bd1SXin Long proto = htons(ETH_P_ERSPAN);
581f551c91dSWilliam Tu } else if (version == 2) {
582c69de58bSWilliam Tu erspan_build_header_v2(skb,
583c69de58bSWilliam Tu ntohl(tunnel_id_to_key32(key->tun_id)),
584c69de58bSWilliam Tu md->u.md2.dir,
585c69de58bSWilliam Tu get_hwid(&md->u.md2),
586c69de58bSWilliam Tu truncate, true);
58720704bd1SXin Long proto = htons(ETH_P_ERSPAN2);
588f551c91dSWilliam Tu } else {
589962924faSwenxu goto err_free_skb;
590f551c91dSWilliam Tu }
5911a66a836SWilliam Tu
5921a66a836SWilliam Tu gre_build_header(skb, 8, TUNNEL_SEQ,
59331c417c9SPeilin Ye proto, 0, htonl(atomic_fetch_inc(&tunnel->o_seqno)));
5941a66a836SWilliam Tu
595962924faSwenxu ip_md_tunnel_xmit(skb, dev, IPPROTO_GRE, tunnel_hlen);
5961a66a836SWilliam Tu
5971a66a836SWilliam Tu return;
5981a66a836SWilliam Tu
5991a66a836SWilliam Tu err_free_skb:
6001a66a836SWilliam Tu kfree_skb(skb);
601c4794d22SEric Dumazet DEV_STATS_INC(dev, tx_dropped);
6021a66a836SWilliam Tu }
6031a66a836SWilliam Tu
gre_fill_metadata_dst(struct net_device * dev,struct sk_buff * skb)604fc4099f1SPravin B Shelar static int gre_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
605fc4099f1SPravin B Shelar {
606fc4099f1SPravin B Shelar struct ip_tunnel_info *info = skb_tunnel_info(skb);
607962924faSwenxu const struct ip_tunnel_key *key;
608fc4099f1SPravin B Shelar struct rtable *rt;
609fc4099f1SPravin B Shelar struct flowi4 fl4;
610fc4099f1SPravin B Shelar
611fc4099f1SPravin B Shelar if (ip_tunnel_info_af(info) != AF_INET)
612fc4099f1SPravin B Shelar return -EINVAL;
613fc4099f1SPravin B Shelar
614962924faSwenxu key = &info->key;
615962924faSwenxu ip_tunnel_init_flow(&fl4, IPPROTO_GRE, key->u.ipv4.dst, key->u.ipv4.src,
616f7716b31SGuillaume Nault tunnel_id_to_key32(key->tun_id),
617db53cd3dSDavid Ahern key->tos & ~INET_ECN_MASK, dev_net(dev), 0,
6187ec9fce4SEyal Birger skb->mark, skb_get_hash(skb), key->flow_flags);
619962924faSwenxu rt = ip_route_output_key(dev_net(dev), &fl4);
620fc4099f1SPravin B Shelar if (IS_ERR(rt))
621fc4099f1SPravin B Shelar return PTR_ERR(rt);
622fc4099f1SPravin B Shelar
623fc4099f1SPravin B Shelar ip_rt_put(rt);
624fc4099f1SPravin B Shelar info->key.u.ipv4.src = fl4.saddr;
625fc4099f1SPravin B Shelar return 0;
626fc4099f1SPravin B Shelar }
627fc4099f1SPravin B Shelar
ipgre_xmit(struct sk_buff * skb,struct net_device * dev)628c5441932SPravin B Shelar static netdev_tx_t ipgre_xmit(struct sk_buff *skb,
629c5441932SPravin B Shelar struct net_device *dev)
630ee34c1ebSMichal Schmidt {
631c5441932SPravin B Shelar struct ip_tunnel *tunnel = netdev_priv(dev);
632c5441932SPravin B Shelar const struct iphdr *tnl_params;
633ee34c1ebSMichal Schmidt
634cb9f1b78SWillem de Bruijn if (!pskb_inet_may_pull(skb))
635cb9f1b78SWillem de Bruijn goto free_skb;
636cb9f1b78SWillem de Bruijn
6372e15ea39SPravin B Shelar if (tunnel->collect_md) {
6382090714eSJiri Benc gre_fb_xmit(skb, dev, skb->protocol);
6392e15ea39SPravin B Shelar return NETDEV_TX_OK;
6402e15ea39SPravin B Shelar }
6412e15ea39SPravin B Shelar
642c5441932SPravin B Shelar if (dev->header_ops) {
64308e3e3daSShigeru Yoshida int pull_len = tunnel->hlen + sizeof(struct iphdr);
64408e3e3daSShigeru Yoshida
645fdafed45SCong Wang if (skb_cow_head(skb, 0))
646c5441932SPravin B Shelar goto free_skb;
647ee34c1ebSMichal Schmidt
648*ea8cad4cSAnton Danilov if (!pskb_may_pull(skb, pull_len))
64908e3e3daSShigeru Yoshida goto free_skb;
65008e3e3daSShigeru Yoshida
651*ea8cad4cSAnton Danilov tnl_params = (const struct iphdr *)skb->data;
652*ea8cad4cSAnton Danilov
65308e3e3daSShigeru Yoshida /* ip_tunnel_xmit() needs skb->data pointing to gre header. */
65408e3e3daSShigeru Yoshida skb_pull(skb, pull_len);
6558a0033a9STimo Teräs skb_reset_mac_header(skb);
6568d21e996SWillem de Bruijn
6578d21e996SWillem de Bruijn if (skb->ip_summed == CHECKSUM_PARTIAL &&
6588d21e996SWillem de Bruijn skb_checksum_start(skb) < skb->data)
6598d21e996SWillem de Bruijn goto free_skb;
660c5441932SPravin B Shelar } else {
661c5441932SPravin B Shelar if (skb_cow_head(skb, dev->needed_headroom))
662c5441932SPravin B Shelar goto free_skb;
663c5441932SPravin B Shelar
664c5441932SPravin B Shelar tnl_params = &tunnel->parms.iph;
665ee34c1ebSMichal Schmidt }
666e1a80002SHerbert Xu
667aed069dfSAlexander Duyck if (gre_handle_offloads(skb, !!(tunnel->parms.o_flags & TUNNEL_CSUM)))
668aed069dfSAlexander Duyck goto free_skb;
6698a0033a9STimo Teräs
670c5441932SPravin B Shelar __gre_xmit(skb, dev, tnl_params, skb->protocol);
671c5441932SPravin B Shelar return NETDEV_TX_OK;
672c5441932SPravin B Shelar
673c5441932SPravin B Shelar free_skb:
6743acfa1e7SEric Dumazet kfree_skb(skb);
675c4794d22SEric Dumazet DEV_STATS_INC(dev, tx_dropped);
676c5441932SPravin B Shelar return NETDEV_TX_OK;
677ee34c1ebSMichal Schmidt }
678ee34c1ebSMichal Schmidt
erspan_xmit(struct sk_buff * skb,struct net_device * dev)67984e54fe0SWilliam Tu static netdev_tx_t erspan_xmit(struct sk_buff *skb,
68084e54fe0SWilliam Tu struct net_device *dev)
68184e54fe0SWilliam Tu {
68284e54fe0SWilliam Tu struct ip_tunnel *tunnel = netdev_priv(dev);
68384e54fe0SWilliam Tu bool truncate = false;
68420704bd1SXin Long __be16 proto;
68584e54fe0SWilliam Tu
686cb9f1b78SWillem de Bruijn if (!pskb_inet_may_pull(skb))
687cb9f1b78SWillem de Bruijn goto free_skb;
688cb9f1b78SWillem de Bruijn
6891a66a836SWilliam Tu if (tunnel->collect_md) {
69020704bd1SXin Long erspan_fb_xmit(skb, dev);
6911a66a836SWilliam Tu return NETDEV_TX_OK;
6921a66a836SWilliam Tu }
6931a66a836SWilliam Tu
69484e54fe0SWilliam Tu if (gre_handle_offloads(skb, false))
69584e54fe0SWilliam Tu goto free_skb;
69684e54fe0SWilliam Tu
69784e54fe0SWilliam Tu if (skb_cow_head(skb, dev->needed_headroom))
69884e54fe0SWilliam Tu goto free_skb;
69984e54fe0SWilliam Tu
700f192970dSWilliam Tu if (skb->len > dev->mtu + dev->hard_header_len) {
701aa7cb378SYuanjun Gong if (pskb_trim(skb, dev->mtu + dev->hard_header_len))
702aa7cb378SYuanjun Gong goto free_skb;
70384e54fe0SWilliam Tu truncate = true;
70484e54fe0SWilliam Tu }
70584e54fe0SWilliam Tu
70684e54fe0SWilliam Tu /* Push ERSPAN header */
707f989d546SWilliam Tu if (tunnel->erspan_ver == 0) {
708f989d546SWilliam Tu proto = htons(ETH_P_ERSPAN);
709f989d546SWilliam Tu tunnel->parms.o_flags &= ~TUNNEL_SEQ;
710f989d546SWilliam Tu } else if (tunnel->erspan_ver == 1) {
711c69de58bSWilliam Tu erspan_build_header(skb, ntohl(tunnel->parms.o_key),
712c69de58bSWilliam Tu tunnel->index,
713a3222dc9SWilliam Tu truncate, true);
71420704bd1SXin Long proto = htons(ETH_P_ERSPAN);
71520704bd1SXin Long } else if (tunnel->erspan_ver == 2) {
716c69de58bSWilliam Tu erspan_build_header_v2(skb, ntohl(tunnel->parms.o_key),
717f551c91dSWilliam Tu tunnel->dir, tunnel->hwid,
718f551c91dSWilliam Tu truncate, true);
71920704bd1SXin Long proto = htons(ETH_P_ERSPAN2);
72020704bd1SXin Long } else {
72102f99df1SWilliam Tu goto free_skb;
72220704bd1SXin Long }
723f551c91dSWilliam Tu
72484e54fe0SWilliam Tu tunnel->parms.o_flags &= ~TUNNEL_KEY;
72520704bd1SXin Long __gre_xmit(skb, dev, &tunnel->parms.iph, proto);
72684e54fe0SWilliam Tu return NETDEV_TX_OK;
72784e54fe0SWilliam Tu
72884e54fe0SWilliam Tu free_skb:
72984e54fe0SWilliam Tu kfree_skb(skb);
730c4794d22SEric Dumazet DEV_STATS_INC(dev, tx_dropped);
73184e54fe0SWilliam Tu return NETDEV_TX_OK;
73284e54fe0SWilliam Tu }
73384e54fe0SWilliam Tu
gre_tap_xmit(struct sk_buff * skb,struct net_device * dev)734c5441932SPravin B Shelar static netdev_tx_t gre_tap_xmit(struct sk_buff *skb,
735c5441932SPravin B Shelar struct net_device *dev)
736c5441932SPravin B Shelar {
737c5441932SPravin B Shelar struct ip_tunnel *tunnel = netdev_priv(dev);
738ee34c1ebSMichal Schmidt
739cb9f1b78SWillem de Bruijn if (!pskb_inet_may_pull(skb))
740cb9f1b78SWillem de Bruijn goto free_skb;
741cb9f1b78SWillem de Bruijn
7422e15ea39SPravin B Shelar if (tunnel->collect_md) {
7432090714eSJiri Benc gre_fb_xmit(skb, dev, htons(ETH_P_TEB));
7442e15ea39SPravin B Shelar return NETDEV_TX_OK;
7452e15ea39SPravin B Shelar }
7462e15ea39SPravin B Shelar
747aed069dfSAlexander Duyck if (gre_handle_offloads(skb, !!(tunnel->parms.o_flags & TUNNEL_CSUM)))
748aed069dfSAlexander Duyck goto free_skb;
749ee34c1ebSMichal Schmidt
750c5441932SPravin B Shelar if (skb_cow_head(skb, dev->needed_headroom))
751c5441932SPravin B Shelar goto free_skb;
75242aa9162SHerbert Xu
753c5441932SPravin B Shelar __gre_xmit(skb, dev, &tunnel->parms.iph, htons(ETH_P_TEB));
754c5441932SPravin B Shelar return NETDEV_TX_OK;
755c5441932SPravin B Shelar
756c5441932SPravin B Shelar free_skb:
7573acfa1e7SEric Dumazet kfree_skb(skb);
758c4794d22SEric Dumazet DEV_STATS_INC(dev, tx_dropped);
759c5441932SPravin B Shelar return NETDEV_TX_OK;
76068c33163SPravin B Shelar }
761ee34c1ebSMichal Schmidt
ipgre_link_update(struct net_device * dev,bool set_mtu)762dd9d598cSXin Long static void ipgre_link_update(struct net_device *dev, bool set_mtu)
763dd9d598cSXin Long {
764dd9d598cSXin Long struct ip_tunnel *tunnel = netdev_priv(dev);
765020e8f60SPeilin Ye __be16 flags;
766dd9d598cSXin Long int len;
767dd9d598cSXin Long
768dd9d598cSXin Long len = tunnel->tun_hlen;
769dd9d598cSXin Long tunnel->tun_hlen = gre_calc_hlen(tunnel->parms.o_flags);
770dd9d598cSXin Long len = tunnel->tun_hlen - len;
771dd9d598cSXin Long tunnel->hlen = tunnel->hlen + len;
772dd9d598cSXin Long
773fdafed45SCong Wang if (dev->header_ops)
774fdafed45SCong Wang dev->hard_header_len += len;
775fdafed45SCong Wang else
776fdafed45SCong Wang dev->needed_headroom += len;
777fdafed45SCong Wang
778dd9d598cSXin Long if (set_mtu)
779dd9d598cSXin Long dev->mtu = max_t(int, dev->mtu - len, 68);
780dd9d598cSXin Long
781020e8f60SPeilin Ye flags = tunnel->parms.o_flags;
782020e8f60SPeilin Ye
783020e8f60SPeilin Ye if (flags & TUNNEL_SEQ ||
784020e8f60SPeilin Ye (flags & TUNNEL_CSUM && tunnel->encap.type != TUNNEL_ENCAP_NONE)) {
7851cc5954fSSabrina Dubroca dev->features &= ~NETIF_F_GSO_SOFTWARE;
7861cc5954fSSabrina Dubroca dev->hw_features &= ~NETIF_F_GSO_SOFTWARE;
7871cc5954fSSabrina Dubroca } else {
788020e8f60SPeilin Ye dev->features |= NETIF_F_GSO_SOFTWARE;
789020e8f60SPeilin Ye dev->hw_features |= NETIF_F_GSO_SOFTWARE;
790dd9d598cSXin Long }
791dd9d598cSXin Long }
792dd9d598cSXin Long
ipgre_tunnel_ctl(struct net_device * dev,struct ip_tunnel_parm * p,int cmd)793607259a6SChristoph Hellwig static int ipgre_tunnel_ctl(struct net_device *dev, struct ip_tunnel_parm *p,
794607259a6SChristoph Hellwig int cmd)
7951da177e4SLinus Torvalds {
796a0efab67SXin Long int err;
7971da177e4SLinus Torvalds
7986c734fb8SCong Wang if (cmd == SIOCADDTUNNEL || cmd == SIOCCHGTUNNEL) {
799607259a6SChristoph Hellwig if (p->iph.version != 4 || p->iph.protocol != IPPROTO_GRE ||
800607259a6SChristoph Hellwig p->iph.ihl != 5 || (p->iph.frag_off & htons(~IP_DF)) ||
801607259a6SChristoph Hellwig ((p->i_flags | p->o_flags) & (GRE_VERSION | GRE_ROUTING)))
8021da177e4SLinus Torvalds return -EINVAL;
803c5441932SPravin B Shelar }
804a0efab67SXin Long
805607259a6SChristoph Hellwig p->i_flags = gre_flags_to_tnl_flags(p->i_flags);
806607259a6SChristoph Hellwig p->o_flags = gre_flags_to_tnl_flags(p->o_flags);
807c5441932SPravin B Shelar
808607259a6SChristoph Hellwig err = ip_tunnel_ctl(dev, p, cmd);
809c5441932SPravin B Shelar if (err)
810c5441932SPravin B Shelar return err;
811c5441932SPravin B Shelar
812a0efab67SXin Long if (cmd == SIOCCHGTUNNEL) {
813a0efab67SXin Long struct ip_tunnel *t = netdev_priv(dev);
814a0efab67SXin Long
815607259a6SChristoph Hellwig t->parms.i_flags = p->i_flags;
816607259a6SChristoph Hellwig t->parms.o_flags = p->o_flags;
817a0efab67SXin Long
818a0efab67SXin Long if (strcmp(dev->rtnl_link_ops->kind, "erspan"))
819a0efab67SXin Long ipgre_link_update(dev, true);
820a0efab67SXin Long }
821a0efab67SXin Long
822607259a6SChristoph Hellwig p->i_flags = gre_tnl_flags_to_gre_flags(p->i_flags);
823607259a6SChristoph Hellwig p->o_flags = gre_tnl_flags_to_gre_flags(p->o_flags);
8241da177e4SLinus Torvalds return 0;
8251da177e4SLinus Torvalds }
8261da177e4SLinus Torvalds
8271da177e4SLinus Torvalds /* Nice toy. Unfortunately, useless in real life :-)
8281da177e4SLinus Torvalds It allows to construct virtual multiprotocol broadcast "LAN"
8291da177e4SLinus Torvalds over the Internet, provided multicast routing is tuned.
8301da177e4SLinus Torvalds
8311da177e4SLinus Torvalds
8321da177e4SLinus Torvalds I have no idea was this bicycle invented before me,
8331da177e4SLinus Torvalds so that I had to set ARPHRD_IPGRE to a random value.
8341da177e4SLinus Torvalds I have an impression, that Cisco could make something similar,
8351da177e4SLinus Torvalds but this feature is apparently missing in IOS<=11.2(8).
8361da177e4SLinus Torvalds
8371da177e4SLinus Torvalds I set up 10.66.66/24 and fec0:6666:6666::0/96 as virtual networks
8381da177e4SLinus Torvalds with broadcast 224.66.66.66. If you have access to mbone, play with me :-)
8391da177e4SLinus Torvalds
8401da177e4SLinus Torvalds ping -t 255 224.66.66.66
8411da177e4SLinus Torvalds
8421da177e4SLinus Torvalds If nobody answers, mbone does not work.
8431da177e4SLinus Torvalds
8441da177e4SLinus Torvalds ip tunnel add Universe mode gre remote 224.66.66.66 local <Your_real_addr> ttl 255
8451da177e4SLinus Torvalds ip addr add 10.66.66.<somewhat>/24 dev Universe
8461da177e4SLinus Torvalds ifconfig Universe up
8471da177e4SLinus Torvalds ifconfig Universe add fe80::<Your_real_addr>/10
8481da177e4SLinus Torvalds ifconfig Universe add fec0:6666:6666::<Your_real_addr>/96
8491da177e4SLinus Torvalds ftp 10.66.66.66
8501da177e4SLinus Torvalds ...
8511da177e4SLinus Torvalds ftp fec0:6666:6666::193.233.7.65
8521da177e4SLinus Torvalds ...
8531da177e4SLinus Torvalds */
ipgre_header(struct sk_buff * skb,struct net_device * dev,unsigned short type,const void * daddr,const void * saddr,unsigned int len)8543b04dddeSStephen Hemminger static int ipgre_header(struct sk_buff *skb, struct net_device *dev,
8553b04dddeSStephen Hemminger unsigned short type,
8561507850bSEric Dumazet const void *daddr, const void *saddr, unsigned int len)
8571da177e4SLinus Torvalds {
8582941a486SPatrick McHardy struct ip_tunnel *t = netdev_priv(dev);
859c5441932SPravin B Shelar struct iphdr *iph;
860c5441932SPravin B Shelar struct gre_base_hdr *greh;
861c5441932SPravin B Shelar
862d58ff351SJohannes Berg iph = skb_push(skb, t->hlen + sizeof(*iph));
863c5441932SPravin B Shelar greh = (struct gre_base_hdr *)(iph+1);
86495f5c64cSTom Herbert greh->flags = gre_tnl_flags_to_gre_flags(t->parms.o_flags);
865c5441932SPravin B Shelar greh->protocol = htons(type);
8661da177e4SLinus Torvalds
8671da177e4SLinus Torvalds memcpy(iph, &t->parms.iph, sizeof(struct iphdr));
8681da177e4SLinus Torvalds
869c5441932SPravin B Shelar /* Set the source hardware address. */
8701da177e4SLinus Torvalds if (saddr)
8711da177e4SLinus Torvalds memcpy(&iph->saddr, saddr, 4);
8726d55cb91STimo Teräs if (daddr)
8731da177e4SLinus Torvalds memcpy(&iph->daddr, daddr, 4);
8746d55cb91STimo Teräs if (iph->daddr)
87577a482bdSTimo Teräs return t->hlen + sizeof(*iph);
8761da177e4SLinus Torvalds
877c5441932SPravin B Shelar return -(t->hlen + sizeof(*iph));
8781da177e4SLinus Torvalds }
8791da177e4SLinus Torvalds
ipgre_header_parse(const struct sk_buff * skb,unsigned char * haddr)8806a5f44d7STimo Teras static int ipgre_header_parse(const struct sk_buff *skb, unsigned char *haddr)
8816a5f44d7STimo Teras {
882b71d1d42SEric Dumazet const struct iphdr *iph = (const struct iphdr *) skb_mac_header(skb);
8836a5f44d7STimo Teras memcpy(haddr, &iph->saddr, 4);
8846a5f44d7STimo Teras return 4;
8856a5f44d7STimo Teras }
8866a5f44d7STimo Teras
8873b04dddeSStephen Hemminger static const struct header_ops ipgre_header_ops = {
8883b04dddeSStephen Hemminger .create = ipgre_header,
8896a5f44d7STimo Teras .parse = ipgre_header_parse,
8903b04dddeSStephen Hemminger };
8913b04dddeSStephen Hemminger
8926a5f44d7STimo Teras #ifdef CONFIG_NET_IPGRE_BROADCAST
ipgre_open(struct net_device * dev)8931da177e4SLinus Torvalds static int ipgre_open(struct net_device *dev)
8941da177e4SLinus Torvalds {
8952941a486SPatrick McHardy struct ip_tunnel *t = netdev_priv(dev);
8961da177e4SLinus Torvalds
897f97c1e0cSJoe Perches if (ipv4_is_multicast(t->parms.iph.daddr)) {
898cbb1e85fSDavid S. Miller struct flowi4 fl4;
899cbb1e85fSDavid S. Miller struct rtable *rt;
900cbb1e85fSDavid S. Miller
901b57708adSNicolas Dichtel rt = ip_route_output_gre(t->net, &fl4,
90278fbfd8aSDavid S. Miller t->parms.iph.daddr,
90378fbfd8aSDavid S. Miller t->parms.iph.saddr,
90478fbfd8aSDavid S. Miller t->parms.o_key,
90578fbfd8aSDavid S. Miller RT_TOS(t->parms.iph.tos),
90678fbfd8aSDavid S. Miller t->parms.link);
907b23dd4feSDavid S. Miller if (IS_ERR(rt))
9081da177e4SLinus Torvalds return -EADDRNOTAVAIL;
909d8d1f30bSChangli Gao dev = rt->dst.dev;
9101da177e4SLinus Torvalds ip_rt_put(rt);
91151456b29SIan Morris if (!__in_dev_get_rtnl(dev))
9121da177e4SLinus Torvalds return -EADDRNOTAVAIL;
9131da177e4SLinus Torvalds t->mlink = dev->ifindex;
914e5ed6399SHerbert Xu ip_mc_inc_group(__in_dev_get_rtnl(dev), t->parms.iph.daddr);
9151da177e4SLinus Torvalds }
9161da177e4SLinus Torvalds return 0;
9171da177e4SLinus Torvalds }
9181da177e4SLinus Torvalds
ipgre_close(struct net_device * dev)9191da177e4SLinus Torvalds static int ipgre_close(struct net_device *dev)
9201da177e4SLinus Torvalds {
9212941a486SPatrick McHardy struct ip_tunnel *t = netdev_priv(dev);
922b8c26a33SStephen Hemminger
923f97c1e0cSJoe Perches if (ipv4_is_multicast(t->parms.iph.daddr) && t->mlink) {
9247fee0ca2SDenis V. Lunev struct in_device *in_dev;
925b57708adSNicolas Dichtel in_dev = inetdev_by_index(t->net, t->mlink);
9268723e1b4SEric Dumazet if (in_dev)
9271da177e4SLinus Torvalds ip_mc_dec_group(in_dev, t->parms.iph.daddr);
9281da177e4SLinus Torvalds }
9291da177e4SLinus Torvalds return 0;
9301da177e4SLinus Torvalds }
9311da177e4SLinus Torvalds #endif
9321da177e4SLinus Torvalds
933b8c26a33SStephen Hemminger static const struct net_device_ops ipgre_netdev_ops = {
934b8c26a33SStephen Hemminger .ndo_init = ipgre_tunnel_init,
935c5441932SPravin B Shelar .ndo_uninit = ip_tunnel_uninit,
936b8c26a33SStephen Hemminger #ifdef CONFIG_NET_IPGRE_BROADCAST
937b8c26a33SStephen Hemminger .ndo_open = ipgre_open,
938b8c26a33SStephen Hemminger .ndo_stop = ipgre_close,
939b8c26a33SStephen Hemminger #endif
940c5441932SPravin B Shelar .ndo_start_xmit = ipgre_xmit,
9413e7a1c7cSArnd Bergmann .ndo_siocdevprivate = ip_tunnel_siocdevprivate,
942c5441932SPravin B Shelar .ndo_change_mtu = ip_tunnel_change_mtu,
94398d7fc46SHeiner Kallweit .ndo_get_stats64 = dev_get_tstats64,
9441e99584bSNicolas Dichtel .ndo_get_iflink = ip_tunnel_get_iflink,
945607259a6SChristoph Hellwig .ndo_tunnel_ctl = ipgre_tunnel_ctl,
946b8c26a33SStephen Hemminger };
947b8c26a33SStephen Hemminger
9486b78f16eSEric Dumazet #define GRE_FEATURES (NETIF_F_SG | \
9496b78f16eSEric Dumazet NETIF_F_FRAGLIST | \
9506b78f16eSEric Dumazet NETIF_F_HIGHDMA | \
9516b78f16eSEric Dumazet NETIF_F_HW_CSUM)
9526b78f16eSEric Dumazet
ipgre_tunnel_setup(struct net_device * dev)9531da177e4SLinus Torvalds static void ipgre_tunnel_setup(struct net_device *dev)
9541da177e4SLinus Torvalds {
955b8c26a33SStephen Hemminger dev->netdev_ops = &ipgre_netdev_ops;
9565a455275SNicolas Dichtel dev->type = ARPHRD_IPGRE;
957c5441932SPravin B Shelar ip_tunnel_setup(dev, ipgre_net_id);
958c5441932SPravin B Shelar }
9591da177e4SLinus Torvalds
__gre_tunnel_init(struct net_device * dev)960c5441932SPravin B Shelar static void __gre_tunnel_init(struct net_device *dev)
961c5441932SPravin B Shelar {
962c5441932SPravin B Shelar struct ip_tunnel *tunnel;
963020e8f60SPeilin Ye __be16 flags;
964c5441932SPravin B Shelar
965c5441932SPravin B Shelar tunnel = netdev_priv(dev);
96695f5c64cSTom Herbert tunnel->tun_hlen = gre_calc_hlen(tunnel->parms.o_flags);
967c5441932SPravin B Shelar tunnel->parms.iph.protocol = IPPROTO_GRE;
968c5441932SPravin B Shelar
9694565e991STom Herbert tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen;
970fdafed45SCong Wang dev->needed_headroom = tunnel->hlen + sizeof(tunnel->parms.iph);
9714565e991STom Herbert
972020e8f60SPeilin Ye dev->features |= GRE_FEATURES | NETIF_F_LLTX;
9736b78f16eSEric Dumazet dev->hw_features |= GRE_FEATURES;
974c5441932SPravin B Shelar
975020e8f60SPeilin Ye flags = tunnel->parms.o_flags;
976020e8f60SPeilin Ye
977020e8f60SPeilin Ye /* TCP offload with GRE SEQ is not supported, nor can we support 2
978020e8f60SPeilin Ye * levels of outer headers requiring an update.
979a0ca153fSAlexander Duyck */
980020e8f60SPeilin Ye if (flags & TUNNEL_SEQ)
981020e8f60SPeilin Ye return;
982020e8f60SPeilin Ye if (flags & TUNNEL_CSUM && tunnel->encap.type != TUNNEL_ENCAP_NONE)
983020e8f60SPeilin Ye return;
984020e8f60SPeilin Ye
985c5441932SPravin B Shelar dev->features |= NETIF_F_GSO_SOFTWARE;
986c5441932SPravin B Shelar dev->hw_features |= NETIF_F_GSO_SOFTWARE;
987a0ca153fSAlexander Duyck }
988a0ca153fSAlexander Duyck
ipgre_tunnel_init(struct net_device * dev)9891da177e4SLinus Torvalds static int ipgre_tunnel_init(struct net_device *dev)
9901da177e4SLinus Torvalds {
991c5441932SPravin B Shelar struct ip_tunnel *tunnel = netdev_priv(dev);
992c5441932SPravin B Shelar struct iphdr *iph = &tunnel->parms.iph;
9931da177e4SLinus Torvalds
994c5441932SPravin B Shelar __gre_tunnel_init(dev);
9951da177e4SLinus Torvalds
9965a1b7e1aSJakub Kicinski __dev_addr_set(dev, &iph->saddr, 4);
997c5441932SPravin B Shelar memcpy(dev->broadcast, &iph->daddr, 4);
9981da177e4SLinus Torvalds
999c5441932SPravin B Shelar dev->flags = IFF_NOARP;
100002875878SEric Dumazet netif_keep_dst(dev);
1001c5441932SPravin B Shelar dev->addr_len = 4;
10021da177e4SLinus Torvalds
1003a64b04d8SJiri Benc if (iph->daddr && !tunnel->collect_md) {
10041da177e4SLinus Torvalds #ifdef CONFIG_NET_IPGRE_BROADCAST
1005f97c1e0cSJoe Perches if (ipv4_is_multicast(iph->daddr)) {
10061da177e4SLinus Torvalds if (!iph->saddr)
10071da177e4SLinus Torvalds return -EINVAL;
10081da177e4SLinus Torvalds dev->flags = IFF_BROADCAST;
10093b04dddeSStephen Hemminger dev->header_ops = &ipgre_header_ops;
1010fdafed45SCong Wang dev->hard_header_len = tunnel->hlen + sizeof(*iph);
1011fdafed45SCong Wang dev->needed_headroom = 0;
10121da177e4SLinus Torvalds }
10131da177e4SLinus Torvalds #endif
1014a64b04d8SJiri Benc } else if (!tunnel->collect_md) {
10156a5f44d7STimo Teras dev->header_ops = &ipgre_header_ops;
1016fdafed45SCong Wang dev->hard_header_len = tunnel->hlen + sizeof(*iph);
1017fdafed45SCong Wang dev->needed_headroom = 0;
1018a64b04d8SJiri Benc }
10191da177e4SLinus Torvalds
1020c5441932SPravin B Shelar return ip_tunnel_init(dev);
102160769a5dSEric Dumazet }
102260769a5dSEric Dumazet
10239f57c67cSPravin B Shelar static const struct gre_protocol ipgre_protocol = {
10249f57c67cSPravin B Shelar .handler = gre_rcv,
10259f57c67cSPravin B Shelar .err_handler = gre_err,
10261da177e4SLinus Torvalds };
10271da177e4SLinus Torvalds
ipgre_init_net(struct net * net)10282c8c1e72SAlexey Dobriyan static int __net_init ipgre_init_net(struct net *net)
102959a4c759SPavel Emelyanov {
1030c5441932SPravin B Shelar return ip_tunnel_init_net(net, ipgre_net_id, &ipgre_link_ops, NULL);
103159a4c759SPavel Emelyanov }
103259a4c759SPavel Emelyanov
ipgre_exit_batch_net(struct list_head * list_net)103364bc1781SEric Dumazet static void __net_exit ipgre_exit_batch_net(struct list_head *list_net)
103459a4c759SPavel Emelyanov {
103564bc1781SEric Dumazet ip_tunnel_delete_nets(list_net, ipgre_net_id, &ipgre_link_ops);
103659a4c759SPavel Emelyanov }
103759a4c759SPavel Emelyanov
103859a4c759SPavel Emelyanov static struct pernet_operations ipgre_net_ops = {
103959a4c759SPavel Emelyanov .init = ipgre_init_net,
104064bc1781SEric Dumazet .exit_batch = ipgre_exit_batch_net,
1041cfb8fbf2SEric W. Biederman .id = &ipgre_net_id,
1042c5441932SPravin B Shelar .size = sizeof(struct ip_tunnel_net),
104359a4c759SPavel Emelyanov };
10441da177e4SLinus Torvalds
ipgre_tunnel_validate(struct nlattr * tb[],struct nlattr * data[],struct netlink_ext_ack * extack)1045a8b8a889SMatthias Schiffer static int ipgre_tunnel_validate(struct nlattr *tb[], struct nlattr *data[],
1046a8b8a889SMatthias Schiffer struct netlink_ext_ack *extack)
1047c19e654dSHerbert Xu {
1048c19e654dSHerbert Xu __be16 flags;
1049c19e654dSHerbert Xu
1050c19e654dSHerbert Xu if (!data)
1051c19e654dSHerbert Xu return 0;
1052c19e654dSHerbert Xu
1053c19e654dSHerbert Xu flags = 0;
1054c19e654dSHerbert Xu if (data[IFLA_GRE_IFLAGS])
1055c19e654dSHerbert Xu flags |= nla_get_be16(data[IFLA_GRE_IFLAGS]);
1056c19e654dSHerbert Xu if (data[IFLA_GRE_OFLAGS])
1057c19e654dSHerbert Xu flags |= nla_get_be16(data[IFLA_GRE_OFLAGS]);
1058c19e654dSHerbert Xu if (flags & (GRE_VERSION|GRE_ROUTING))
1059c19e654dSHerbert Xu return -EINVAL;
1060c19e654dSHerbert Xu
1061946b636fSJiri Benc if (data[IFLA_GRE_COLLECT_METADATA] &&
1062946b636fSJiri Benc data[IFLA_GRE_ENCAP_TYPE] &&
1063946b636fSJiri Benc nla_get_u16(data[IFLA_GRE_ENCAP_TYPE]) != TUNNEL_ENCAP_NONE)
1064946b636fSJiri Benc return -EINVAL;
1065946b636fSJiri Benc
1066c19e654dSHerbert Xu return 0;
1067c19e654dSHerbert Xu }
1068c19e654dSHerbert Xu
ipgre_tap_validate(struct nlattr * tb[],struct nlattr * data[],struct netlink_ext_ack * extack)1069a8b8a889SMatthias Schiffer static int ipgre_tap_validate(struct nlattr *tb[], struct nlattr *data[],
1070a8b8a889SMatthias Schiffer struct netlink_ext_ack *extack)
1071e1a80002SHerbert Xu {
1072e1a80002SHerbert Xu __be32 daddr;
1073e1a80002SHerbert Xu
1074e1a80002SHerbert Xu if (tb[IFLA_ADDRESS]) {
1075e1a80002SHerbert Xu if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN)
1076e1a80002SHerbert Xu return -EINVAL;
1077e1a80002SHerbert Xu if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS])))
1078e1a80002SHerbert Xu return -EADDRNOTAVAIL;
1079e1a80002SHerbert Xu }
1080e1a80002SHerbert Xu
1081e1a80002SHerbert Xu if (!data)
1082e1a80002SHerbert Xu goto out;
1083e1a80002SHerbert Xu
1084e1a80002SHerbert Xu if (data[IFLA_GRE_REMOTE]) {
1085e1a80002SHerbert Xu memcpy(&daddr, nla_data(data[IFLA_GRE_REMOTE]), 4);
1086e1a80002SHerbert Xu if (!daddr)
1087e1a80002SHerbert Xu return -EINVAL;
1088e1a80002SHerbert Xu }
1089e1a80002SHerbert Xu
1090e1a80002SHerbert Xu out:
1091a8b8a889SMatthias Schiffer return ipgre_tunnel_validate(tb, data, extack);
1092e1a80002SHerbert Xu }
1093e1a80002SHerbert Xu
erspan_validate(struct nlattr * tb[],struct nlattr * data[],struct netlink_ext_ack * extack)109484e54fe0SWilliam Tu static int erspan_validate(struct nlattr *tb[], struct nlattr *data[],
109584e54fe0SWilliam Tu struct netlink_ext_ack *extack)
109684e54fe0SWilliam Tu {
109784e54fe0SWilliam Tu __be16 flags = 0;
109884e54fe0SWilliam Tu int ret;
109984e54fe0SWilliam Tu
110084e54fe0SWilliam Tu if (!data)
110184e54fe0SWilliam Tu return 0;
110284e54fe0SWilliam Tu
110384e54fe0SWilliam Tu ret = ipgre_tap_validate(tb, data, extack);
110484e54fe0SWilliam Tu if (ret)
110584e54fe0SWilliam Tu return ret;
110684e54fe0SWilliam Tu
110751fa960dSWilliam Tu if (data[IFLA_GRE_ERSPAN_VER] &&
110851fa960dSWilliam Tu nla_get_u8(data[IFLA_GRE_ERSPAN_VER]) == 0)
1109f989d546SWilliam Tu return 0;
1110f989d546SWilliam Tu
1111f989d546SWilliam Tu /* ERSPAN type II/III should only have GRE sequence and key flag */
11121a66a836SWilliam Tu if (data[IFLA_GRE_OFLAGS])
111384e54fe0SWilliam Tu flags |= nla_get_be16(data[IFLA_GRE_OFLAGS]);
11141a66a836SWilliam Tu if (data[IFLA_GRE_IFLAGS])
111584e54fe0SWilliam Tu flags |= nla_get_be16(data[IFLA_GRE_IFLAGS]);
11161a66a836SWilliam Tu if (!data[IFLA_GRE_COLLECT_METADATA] &&
11171a66a836SWilliam Tu flags != (GRE_SEQ | GRE_KEY))
111884e54fe0SWilliam Tu return -EINVAL;
111984e54fe0SWilliam Tu
112084e54fe0SWilliam Tu /* ERSPAN Session ID only has 10-bit. Since we reuse
112184e54fe0SWilliam Tu * 32-bit key field as ID, check it's range.
112284e54fe0SWilliam Tu */
112384e54fe0SWilliam Tu if (data[IFLA_GRE_IKEY] &&
112484e54fe0SWilliam Tu (ntohl(nla_get_be32(data[IFLA_GRE_IKEY])) & ~ID_MASK))
112584e54fe0SWilliam Tu return -EINVAL;
112684e54fe0SWilliam Tu
112784e54fe0SWilliam Tu if (data[IFLA_GRE_OKEY] &&
112884e54fe0SWilliam Tu (ntohl(nla_get_be32(data[IFLA_GRE_OKEY])) & ~ID_MASK))
112984e54fe0SWilliam Tu return -EINVAL;
113084e54fe0SWilliam Tu
113184e54fe0SWilliam Tu return 0;
113284e54fe0SWilliam Tu }
113384e54fe0SWilliam Tu
ipgre_netlink_parms(struct net_device * dev,struct nlattr * data[],struct nlattr * tb[],struct ip_tunnel_parm * parms,__u32 * fwmark)113422a59be8SPhilip Prindeville static int ipgre_netlink_parms(struct net_device *dev,
11352e15ea39SPravin B Shelar struct nlattr *data[],
11362e15ea39SPravin B Shelar struct nlattr *tb[],
11379830ad4cSCraig Gallek struct ip_tunnel_parm *parms,
11389830ad4cSCraig Gallek __u32 *fwmark)
1139c19e654dSHerbert Xu {
114022a59be8SPhilip Prindeville struct ip_tunnel *t = netdev_priv(dev);
114122a59be8SPhilip Prindeville
11427bb82d92SHerbert Xu memset(parms, 0, sizeof(*parms));
1143c19e654dSHerbert Xu
1144c19e654dSHerbert Xu parms->iph.protocol = IPPROTO_GRE;
1145c19e654dSHerbert Xu
1146c19e654dSHerbert Xu if (!data)
114722a59be8SPhilip Prindeville return 0;
1148c19e654dSHerbert Xu
1149c19e654dSHerbert Xu if (data[IFLA_GRE_LINK])
1150c19e654dSHerbert Xu parms->link = nla_get_u32(data[IFLA_GRE_LINK]);
1151c19e654dSHerbert Xu
1152c19e654dSHerbert Xu if (data[IFLA_GRE_IFLAGS])
1153c5441932SPravin B Shelar parms->i_flags = gre_flags_to_tnl_flags(nla_get_be16(data[IFLA_GRE_IFLAGS]));
1154c19e654dSHerbert Xu
1155c19e654dSHerbert Xu if (data[IFLA_GRE_OFLAGS])
1156c5441932SPravin B Shelar parms->o_flags = gre_flags_to_tnl_flags(nla_get_be16(data[IFLA_GRE_OFLAGS]));
1157c19e654dSHerbert Xu
1158c19e654dSHerbert Xu if (data[IFLA_GRE_IKEY])
1159c19e654dSHerbert Xu parms->i_key = nla_get_be32(data[IFLA_GRE_IKEY]);
1160c19e654dSHerbert Xu
1161c19e654dSHerbert Xu if (data[IFLA_GRE_OKEY])
1162c19e654dSHerbert Xu parms->o_key = nla_get_be32(data[IFLA_GRE_OKEY]);
1163c19e654dSHerbert Xu
1164c19e654dSHerbert Xu if (data[IFLA_GRE_LOCAL])
116567b61f6cSJiri Benc parms->iph.saddr = nla_get_in_addr(data[IFLA_GRE_LOCAL]);
1166c19e654dSHerbert Xu
1167c19e654dSHerbert Xu if (data[IFLA_GRE_REMOTE])
116867b61f6cSJiri Benc parms->iph.daddr = nla_get_in_addr(data[IFLA_GRE_REMOTE]);
1169c19e654dSHerbert Xu
1170c19e654dSHerbert Xu if (data[IFLA_GRE_TTL])
1171c19e654dSHerbert Xu parms->iph.ttl = nla_get_u8(data[IFLA_GRE_TTL]);
1172c19e654dSHerbert Xu
1173c19e654dSHerbert Xu if (data[IFLA_GRE_TOS])
1174c19e654dSHerbert Xu parms->iph.tos = nla_get_u8(data[IFLA_GRE_TOS]);
1175c19e654dSHerbert Xu
117622a59be8SPhilip Prindeville if (!data[IFLA_GRE_PMTUDISC] || nla_get_u8(data[IFLA_GRE_PMTUDISC])) {
117722a59be8SPhilip Prindeville if (t->ignore_df)
117822a59be8SPhilip Prindeville return -EINVAL;
1179c19e654dSHerbert Xu parms->iph.frag_off = htons(IP_DF);
118022a59be8SPhilip Prindeville }
11812e15ea39SPravin B Shelar
11822e15ea39SPravin B Shelar if (data[IFLA_GRE_COLLECT_METADATA]) {
11832e15ea39SPravin B Shelar t->collect_md = true;
1184e271c7b4SJiri Benc if (dev->type == ARPHRD_IPGRE)
1185e271c7b4SJiri Benc dev->type = ARPHRD_NONE;
11862e15ea39SPravin B Shelar }
118722a59be8SPhilip Prindeville
118822a59be8SPhilip Prindeville if (data[IFLA_GRE_IGNORE_DF]) {
118922a59be8SPhilip Prindeville if (nla_get_u8(data[IFLA_GRE_IGNORE_DF])
119022a59be8SPhilip Prindeville && (parms->iph.frag_off & htons(IP_DF)))
119122a59be8SPhilip Prindeville return -EINVAL;
119222a59be8SPhilip Prindeville t->ignore_df = !!nla_get_u8(data[IFLA_GRE_IGNORE_DF]);
119322a59be8SPhilip Prindeville }
119422a59be8SPhilip Prindeville
11959830ad4cSCraig Gallek if (data[IFLA_GRE_FWMARK])
11969830ad4cSCraig Gallek *fwmark = nla_get_u32(data[IFLA_GRE_FWMARK]);
11979830ad4cSCraig Gallek
1198e1f8f78fSPetr Machata return 0;
1199e1f8f78fSPetr Machata }
1200e1f8f78fSPetr Machata
erspan_netlink_parms(struct net_device * dev,struct nlattr * data[],struct nlattr * tb[],struct ip_tunnel_parm * parms,__u32 * fwmark)1201e1f8f78fSPetr Machata static int erspan_netlink_parms(struct net_device *dev,
1202e1f8f78fSPetr Machata struct nlattr *data[],
1203e1f8f78fSPetr Machata struct nlattr *tb[],
1204e1f8f78fSPetr Machata struct ip_tunnel_parm *parms,
1205e1f8f78fSPetr Machata __u32 *fwmark)
1206e1f8f78fSPetr Machata {
1207e1f8f78fSPetr Machata struct ip_tunnel *t = netdev_priv(dev);
1208e1f8f78fSPetr Machata int err;
1209e1f8f78fSPetr Machata
1210e1f8f78fSPetr Machata err = ipgre_netlink_parms(dev, data, tb, parms, fwmark);
1211e1f8f78fSPetr Machata if (err)
1212e1f8f78fSPetr Machata return err;
121332ca98feSPetr Machata if (!data)
121432ca98feSPetr Machata return 0;
1215e1f8f78fSPetr Machata
1216f551c91dSWilliam Tu if (data[IFLA_GRE_ERSPAN_VER]) {
1217f551c91dSWilliam Tu t->erspan_ver = nla_get_u8(data[IFLA_GRE_ERSPAN_VER]);
1218f551c91dSWilliam Tu
1219f989d546SWilliam Tu if (t->erspan_ver > 2)
1220f551c91dSWilliam Tu return -EINVAL;
1221f551c91dSWilliam Tu }
1222f551c91dSWilliam Tu
1223f551c91dSWilliam Tu if (t->erspan_ver == 1) {
122484e54fe0SWilliam Tu if (data[IFLA_GRE_ERSPAN_INDEX]) {
122584e54fe0SWilliam Tu t->index = nla_get_u32(data[IFLA_GRE_ERSPAN_INDEX]);
122684e54fe0SWilliam Tu if (t->index & ~INDEX_MASK)
122784e54fe0SWilliam Tu return -EINVAL;
122884e54fe0SWilliam Tu }
1229f551c91dSWilliam Tu } else if (t->erspan_ver == 2) {
1230f551c91dSWilliam Tu if (data[IFLA_GRE_ERSPAN_DIR]) {
1231f551c91dSWilliam Tu t->dir = nla_get_u8(data[IFLA_GRE_ERSPAN_DIR]);
1232f551c91dSWilliam Tu if (t->dir & ~(DIR_MASK >> DIR_OFFSET))
1233f551c91dSWilliam Tu return -EINVAL;
1234f551c91dSWilliam Tu }
1235f551c91dSWilliam Tu if (data[IFLA_GRE_ERSPAN_HWID]) {
1236f551c91dSWilliam Tu t->hwid = nla_get_u16(data[IFLA_GRE_ERSPAN_HWID]);
1237f551c91dSWilliam Tu if (t->hwid & ~(HWID_MASK >> HWID_OFFSET))
1238f551c91dSWilliam Tu return -EINVAL;
1239f551c91dSWilliam Tu }
1240f551c91dSWilliam Tu }
124184e54fe0SWilliam Tu
124222a59be8SPhilip Prindeville return 0;
1243c19e654dSHerbert Xu }
1244c19e654dSHerbert Xu
12454565e991STom Herbert /* This function returns true when ENCAP attributes are present in the nl msg */
ipgre_netlink_encap_parms(struct nlattr * data[],struct ip_tunnel_encap * ipencap)12464565e991STom Herbert static bool ipgre_netlink_encap_parms(struct nlattr *data[],
12474565e991STom Herbert struct ip_tunnel_encap *ipencap)
12484565e991STom Herbert {
12494565e991STom Herbert bool ret = false;
12504565e991STom Herbert
12514565e991STom Herbert memset(ipencap, 0, sizeof(*ipencap));
12524565e991STom Herbert
12534565e991STom Herbert if (!data)
12544565e991STom Herbert return ret;
12554565e991STom Herbert
12564565e991STom Herbert if (data[IFLA_GRE_ENCAP_TYPE]) {
12574565e991STom Herbert ret = true;
12584565e991STom Herbert ipencap->type = nla_get_u16(data[IFLA_GRE_ENCAP_TYPE]);
12594565e991STom Herbert }
12604565e991STom Herbert
12614565e991STom Herbert if (data[IFLA_GRE_ENCAP_FLAGS]) {
12624565e991STom Herbert ret = true;
12634565e991STom Herbert ipencap->flags = nla_get_u16(data[IFLA_GRE_ENCAP_FLAGS]);
12644565e991STom Herbert }
12654565e991STom Herbert
12664565e991STom Herbert if (data[IFLA_GRE_ENCAP_SPORT]) {
12674565e991STom Herbert ret = true;
12683e97fa70SSabrina Dubroca ipencap->sport = nla_get_be16(data[IFLA_GRE_ENCAP_SPORT]);
12694565e991STom Herbert }
12704565e991STom Herbert
12714565e991STom Herbert if (data[IFLA_GRE_ENCAP_DPORT]) {
12724565e991STom Herbert ret = true;
12733e97fa70SSabrina Dubroca ipencap->dport = nla_get_be16(data[IFLA_GRE_ENCAP_DPORT]);
12744565e991STom Herbert }
12754565e991STom Herbert
12764565e991STom Herbert return ret;
12774565e991STom Herbert }
12784565e991STom Herbert
gre_tap_init(struct net_device * dev)1279c5441932SPravin B Shelar static int gre_tap_init(struct net_device *dev)
1280e1a80002SHerbert Xu {
1281c5441932SPravin B Shelar __gre_tunnel_init(dev);
1282bec94d43Sstephen hemminger dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
1283d51711c0SXin Long netif_keep_dst(dev);
1284e1a80002SHerbert Xu
1285c5441932SPravin B Shelar return ip_tunnel_init(dev);
1286e1a80002SHerbert Xu }
1287e1a80002SHerbert Xu
1288c5441932SPravin B Shelar static const struct net_device_ops gre_tap_netdev_ops = {
1289c5441932SPravin B Shelar .ndo_init = gre_tap_init,
1290c5441932SPravin B Shelar .ndo_uninit = ip_tunnel_uninit,
1291c5441932SPravin B Shelar .ndo_start_xmit = gre_tap_xmit,
1292b8c26a33SStephen Hemminger .ndo_set_mac_address = eth_mac_addr,
1293b8c26a33SStephen Hemminger .ndo_validate_addr = eth_validate_addr,
1294c5441932SPravin B Shelar .ndo_change_mtu = ip_tunnel_change_mtu,
129598d7fc46SHeiner Kallweit .ndo_get_stats64 = dev_get_tstats64,
12961e99584bSNicolas Dichtel .ndo_get_iflink = ip_tunnel_get_iflink,
1297fc4099f1SPravin B Shelar .ndo_fill_metadata_dst = gre_fill_metadata_dst,
1298b8c26a33SStephen Hemminger };
1299b8c26a33SStephen Hemminger
erspan_tunnel_init(struct net_device * dev)130084e54fe0SWilliam Tu static int erspan_tunnel_init(struct net_device *dev)
130184e54fe0SWilliam Tu {
130284e54fe0SWilliam Tu struct ip_tunnel *tunnel = netdev_priv(dev);
130384e54fe0SWilliam Tu
1304f989d546SWilliam Tu if (tunnel->erspan_ver == 0)
1305f989d546SWilliam Tu tunnel->tun_hlen = 4; /* 4-byte GRE hdr. */
1306f989d546SWilliam Tu else
1307f989d546SWilliam Tu tunnel->tun_hlen = 8; /* 8-byte GRE hdr. */
1308f989d546SWilliam Tu
130984e54fe0SWilliam Tu tunnel->parms.iph.protocol = IPPROTO_GRE;
1310c122fda2SXin Long tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen +
1311f551c91dSWilliam Tu erspan_hdr_len(tunnel->erspan_ver);
131284e54fe0SWilliam Tu
131384e54fe0SWilliam Tu dev->features |= GRE_FEATURES;
131484e54fe0SWilliam Tu dev->hw_features |= GRE_FEATURES;
131584e54fe0SWilliam Tu dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
1316c84bed44SXin Long netif_keep_dst(dev);
131784e54fe0SWilliam Tu
131884e54fe0SWilliam Tu return ip_tunnel_init(dev);
131984e54fe0SWilliam Tu }
132084e54fe0SWilliam Tu
132184e54fe0SWilliam Tu static const struct net_device_ops erspan_netdev_ops = {
132284e54fe0SWilliam Tu .ndo_init = erspan_tunnel_init,
132384e54fe0SWilliam Tu .ndo_uninit = ip_tunnel_uninit,
132484e54fe0SWilliam Tu .ndo_start_xmit = erspan_xmit,
132584e54fe0SWilliam Tu .ndo_set_mac_address = eth_mac_addr,
132684e54fe0SWilliam Tu .ndo_validate_addr = eth_validate_addr,
132784e54fe0SWilliam Tu .ndo_change_mtu = ip_tunnel_change_mtu,
132898d7fc46SHeiner Kallweit .ndo_get_stats64 = dev_get_tstats64,
132984e54fe0SWilliam Tu .ndo_get_iflink = ip_tunnel_get_iflink,
133084e54fe0SWilliam Tu .ndo_fill_metadata_dst = gre_fill_metadata_dst,
133184e54fe0SWilliam Tu };
133284e54fe0SWilliam Tu
ipgre_tap_setup(struct net_device * dev)1333e1a80002SHerbert Xu static void ipgre_tap_setup(struct net_device *dev)
1334e1a80002SHerbert Xu {
1335e1a80002SHerbert Xu ether_setup(dev);
1336cfddd4c3SXin Long dev->max_mtu = 0;
1337c5441932SPravin B Shelar dev->netdev_ops = &gre_tap_netdev_ops;
1338d13b161cSJiri Benc dev->priv_flags &= ~IFF_TX_SKB_SHARING;
1339f8c1b7ceSstephen hemminger dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
1340c5441932SPravin B Shelar ip_tunnel_setup(dev, gre_tap_net_id);
1341e1a80002SHerbert Xu }
1342e1a80002SHerbert Xu
1343e1f8f78fSPetr Machata static int
ipgre_newlink_encap_setup(struct net_device * dev,struct nlattr * data[])1344e1f8f78fSPetr Machata ipgre_newlink_encap_setup(struct net_device *dev, struct nlattr *data[])
1345c19e654dSHerbert Xu {
13464565e991STom Herbert struct ip_tunnel_encap ipencap;
13474565e991STom Herbert
13484565e991STom Herbert if (ipgre_netlink_encap_parms(data, &ipencap)) {
13494565e991STom Herbert struct ip_tunnel *t = netdev_priv(dev);
1350e1f8f78fSPetr Machata int err = ip_tunnel_encap_setup(t, &ipencap);
13514565e991STom Herbert
13524565e991STom Herbert if (err < 0)
13534565e991STom Herbert return err;
13544565e991STom Herbert }
1355c19e654dSHerbert Xu
1356e1f8f78fSPetr Machata return 0;
1357e1f8f78fSPetr Machata }
1358e1f8f78fSPetr Machata
ipgre_newlink(struct net * src_net,struct net_device * dev,struct nlattr * tb[],struct nlattr * data[],struct netlink_ext_ack * extack)1359e1f8f78fSPetr Machata static int ipgre_newlink(struct net *src_net, struct net_device *dev,
1360e1f8f78fSPetr Machata struct nlattr *tb[], struct nlattr *data[],
1361e1f8f78fSPetr Machata struct netlink_ext_ack *extack)
1362e1f8f78fSPetr Machata {
1363e1f8f78fSPetr Machata struct ip_tunnel_parm p;
1364e1f8f78fSPetr Machata __u32 fwmark = 0;
1365e1f8f78fSPetr Machata int err;
1366e1f8f78fSPetr Machata
1367e1f8f78fSPetr Machata err = ipgre_newlink_encap_setup(dev, data);
1368e1f8f78fSPetr Machata if (err)
1369e1f8f78fSPetr Machata return err;
1370e1f8f78fSPetr Machata
13719830ad4cSCraig Gallek err = ipgre_netlink_parms(dev, data, tb, &p, &fwmark);
137222a59be8SPhilip Prindeville if (err < 0)
137322a59be8SPhilip Prindeville return err;
13749830ad4cSCraig Gallek return ip_tunnel_newlink(dev, tb, &p, fwmark);
1375c19e654dSHerbert Xu }
1376c19e654dSHerbert Xu
erspan_newlink(struct net * src_net,struct net_device * dev,struct nlattr * tb[],struct nlattr * data[],struct netlink_ext_ack * extack)1377e1f8f78fSPetr Machata static int erspan_newlink(struct net *src_net, struct net_device *dev,
1378e1f8f78fSPetr Machata struct nlattr *tb[], struct nlattr *data[],
1379e1f8f78fSPetr Machata struct netlink_ext_ack *extack)
1380e1f8f78fSPetr Machata {
1381e1f8f78fSPetr Machata struct ip_tunnel_parm p;
1382e1f8f78fSPetr Machata __u32 fwmark = 0;
1383e1f8f78fSPetr Machata int err;
1384e1f8f78fSPetr Machata
1385e1f8f78fSPetr Machata err = ipgre_newlink_encap_setup(dev, data);
1386e1f8f78fSPetr Machata if (err)
1387e1f8f78fSPetr Machata return err;
1388e1f8f78fSPetr Machata
1389e1f8f78fSPetr Machata err = erspan_netlink_parms(dev, data, tb, &p, &fwmark);
1390e1f8f78fSPetr Machata if (err)
1391e1f8f78fSPetr Machata return err;
1392e1f8f78fSPetr Machata return ip_tunnel_newlink(dev, tb, &p, fwmark);
1393e1f8f78fSPetr Machata }
1394e1f8f78fSPetr Machata
ipgre_changelink(struct net_device * dev,struct nlattr * tb[],struct nlattr * data[],struct netlink_ext_ack * extack)1395c19e654dSHerbert Xu static int ipgre_changelink(struct net_device *dev, struct nlattr *tb[],
1396ad744b22SMatthias Schiffer struct nlattr *data[],
1397ad744b22SMatthias Schiffer struct netlink_ext_ack *extack)
1398c19e654dSHerbert Xu {
13999830ad4cSCraig Gallek struct ip_tunnel *t = netdev_priv(dev);
14009830ad4cSCraig Gallek __u32 fwmark = t->fwmark;
1401dd9d598cSXin Long struct ip_tunnel_parm p;
140222a59be8SPhilip Prindeville int err;
14034565e991STom Herbert
1404e1f8f78fSPetr Machata err = ipgre_newlink_encap_setup(dev, data);
1405e1f8f78fSPetr Machata if (err)
14064565e991STom Herbert return err;
1407c19e654dSHerbert Xu
14089830ad4cSCraig Gallek err = ipgre_netlink_parms(dev, data, tb, &p, &fwmark);
140922a59be8SPhilip Prindeville if (err < 0)
141022a59be8SPhilip Prindeville return err;
1411dd9d598cSXin Long
1412dd9d598cSXin Long err = ip_tunnel_changelink(dev, tb, &p, fwmark);
1413dd9d598cSXin Long if (err < 0)
1414dd9d598cSXin Long return err;
1415dd9d598cSXin Long
1416dd9d598cSXin Long t->parms.i_flags = p.i_flags;
1417dd9d598cSXin Long t->parms.o_flags = p.o_flags;
1418dd9d598cSXin Long
1419dd9d598cSXin Long ipgre_link_update(dev, !tb[IFLA_MTU]);
1420dd9d598cSXin Long
1421dd9d598cSXin Long return 0;
1422c19e654dSHerbert Xu }
1423c19e654dSHerbert Xu
erspan_changelink(struct net_device * dev,struct nlattr * tb[],struct nlattr * data[],struct netlink_ext_ack * extack)1424e1f8f78fSPetr Machata static int erspan_changelink(struct net_device *dev, struct nlattr *tb[],
1425e1f8f78fSPetr Machata struct nlattr *data[],
1426e1f8f78fSPetr Machata struct netlink_ext_ack *extack)
1427e1f8f78fSPetr Machata {
1428e1f8f78fSPetr Machata struct ip_tunnel *t = netdev_priv(dev);
1429e1f8f78fSPetr Machata __u32 fwmark = t->fwmark;
1430e1f8f78fSPetr Machata struct ip_tunnel_parm p;
1431e1f8f78fSPetr Machata int err;
1432e1f8f78fSPetr Machata
1433e1f8f78fSPetr Machata err = ipgre_newlink_encap_setup(dev, data);
1434e1f8f78fSPetr Machata if (err)
1435e1f8f78fSPetr Machata return err;
1436e1f8f78fSPetr Machata
1437e1f8f78fSPetr Machata err = erspan_netlink_parms(dev, data, tb, &p, &fwmark);
1438e1f8f78fSPetr Machata if (err < 0)
1439e1f8f78fSPetr Machata return err;
1440e1f8f78fSPetr Machata
1441e1f8f78fSPetr Machata err = ip_tunnel_changelink(dev, tb, &p, fwmark);
1442e1f8f78fSPetr Machata if (err < 0)
1443e1f8f78fSPetr Machata return err;
1444e1f8f78fSPetr Machata
1445e1f8f78fSPetr Machata t->parms.i_flags = p.i_flags;
1446e1f8f78fSPetr Machata t->parms.o_flags = p.o_flags;
1447e1f8f78fSPetr Machata
1448e1f8f78fSPetr Machata return 0;
1449e1f8f78fSPetr Machata }
1450e1f8f78fSPetr Machata
ipgre_get_size(const struct net_device * dev)1451c19e654dSHerbert Xu static size_t ipgre_get_size(const struct net_device *dev)
1452c19e654dSHerbert Xu {
1453c19e654dSHerbert Xu return
1454c19e654dSHerbert Xu /* IFLA_GRE_LINK */
1455c19e654dSHerbert Xu nla_total_size(4) +
1456c19e654dSHerbert Xu /* IFLA_GRE_IFLAGS */
1457c19e654dSHerbert Xu nla_total_size(2) +
1458c19e654dSHerbert Xu /* IFLA_GRE_OFLAGS */
1459c19e654dSHerbert Xu nla_total_size(2) +
1460c19e654dSHerbert Xu /* IFLA_GRE_IKEY */
1461c19e654dSHerbert Xu nla_total_size(4) +
1462c19e654dSHerbert Xu /* IFLA_GRE_OKEY */
1463c19e654dSHerbert Xu nla_total_size(4) +
1464c19e654dSHerbert Xu /* IFLA_GRE_LOCAL */
1465c19e654dSHerbert Xu nla_total_size(4) +
1466c19e654dSHerbert Xu /* IFLA_GRE_REMOTE */
1467c19e654dSHerbert Xu nla_total_size(4) +
1468c19e654dSHerbert Xu /* IFLA_GRE_TTL */
1469c19e654dSHerbert Xu nla_total_size(1) +
1470c19e654dSHerbert Xu /* IFLA_GRE_TOS */
1471c19e654dSHerbert Xu nla_total_size(1) +
1472c19e654dSHerbert Xu /* IFLA_GRE_PMTUDISC */
1473c19e654dSHerbert Xu nla_total_size(1) +
14744565e991STom Herbert /* IFLA_GRE_ENCAP_TYPE */
14754565e991STom Herbert nla_total_size(2) +
14764565e991STom Herbert /* IFLA_GRE_ENCAP_FLAGS */
14774565e991STom Herbert nla_total_size(2) +
14784565e991STom Herbert /* IFLA_GRE_ENCAP_SPORT */
14794565e991STom Herbert nla_total_size(2) +
14804565e991STom Herbert /* IFLA_GRE_ENCAP_DPORT */
14814565e991STom Herbert nla_total_size(2) +
14822e15ea39SPravin B Shelar /* IFLA_GRE_COLLECT_METADATA */
14832e15ea39SPravin B Shelar nla_total_size(0) +
148422a59be8SPhilip Prindeville /* IFLA_GRE_IGNORE_DF */
148522a59be8SPhilip Prindeville nla_total_size(1) +
14869830ad4cSCraig Gallek /* IFLA_GRE_FWMARK */
14879830ad4cSCraig Gallek nla_total_size(4) +
148884e54fe0SWilliam Tu /* IFLA_GRE_ERSPAN_INDEX */
148984e54fe0SWilliam Tu nla_total_size(4) +
1490f551c91dSWilliam Tu /* IFLA_GRE_ERSPAN_VER */
1491f551c91dSWilliam Tu nla_total_size(1) +
1492f551c91dSWilliam Tu /* IFLA_GRE_ERSPAN_DIR */
1493f551c91dSWilliam Tu nla_total_size(1) +
1494f551c91dSWilliam Tu /* IFLA_GRE_ERSPAN_HWID */
1495f551c91dSWilliam Tu nla_total_size(2) +
1496c19e654dSHerbert Xu 0;
1497c19e654dSHerbert Xu }
1498c19e654dSHerbert Xu
ipgre_fill_info(struct sk_buff * skb,const struct net_device * dev)1499c19e654dSHerbert Xu static int ipgre_fill_info(struct sk_buff *skb, const struct net_device *dev)
1500c19e654dSHerbert Xu {
1501c19e654dSHerbert Xu struct ip_tunnel *t = netdev_priv(dev);
1502c19e654dSHerbert Xu struct ip_tunnel_parm *p = &t->parms;
1503feaf5c79SLorenzo Bianconi __be16 o_flags = p->o_flags;
1504feaf5c79SLorenzo Bianconi
1505f3756b79SDavid S. Miller if (nla_put_u32(skb, IFLA_GRE_LINK, p->link) ||
150695f5c64cSTom Herbert nla_put_be16(skb, IFLA_GRE_IFLAGS,
150795f5c64cSTom Herbert gre_tnl_flags_to_gre_flags(p->i_flags)) ||
150895f5c64cSTom Herbert nla_put_be16(skb, IFLA_GRE_OFLAGS,
1509feaf5c79SLorenzo Bianconi gre_tnl_flags_to_gre_flags(o_flags)) ||
1510f3756b79SDavid S. Miller nla_put_be32(skb, IFLA_GRE_IKEY, p->i_key) ||
1511f3756b79SDavid S. Miller nla_put_be32(skb, IFLA_GRE_OKEY, p->o_key) ||
1512930345eaSJiri Benc nla_put_in_addr(skb, IFLA_GRE_LOCAL, p->iph.saddr) ||
1513930345eaSJiri Benc nla_put_in_addr(skb, IFLA_GRE_REMOTE, p->iph.daddr) ||
1514f3756b79SDavid S. Miller nla_put_u8(skb, IFLA_GRE_TTL, p->iph.ttl) ||
1515f3756b79SDavid S. Miller nla_put_u8(skb, IFLA_GRE_TOS, p->iph.tos) ||
1516f3756b79SDavid S. Miller nla_put_u8(skb, IFLA_GRE_PMTUDISC,
15179830ad4cSCraig Gallek !!(p->iph.frag_off & htons(IP_DF))) ||
15189830ad4cSCraig Gallek nla_put_u32(skb, IFLA_GRE_FWMARK, t->fwmark))
1519f3756b79SDavid S. Miller goto nla_put_failure;
15204565e991STom Herbert
15214565e991STom Herbert if (nla_put_u16(skb, IFLA_GRE_ENCAP_TYPE,
15224565e991STom Herbert t->encap.type) ||
15233e97fa70SSabrina Dubroca nla_put_be16(skb, IFLA_GRE_ENCAP_SPORT,
15244565e991STom Herbert t->encap.sport) ||
15253e97fa70SSabrina Dubroca nla_put_be16(skb, IFLA_GRE_ENCAP_DPORT,
15264565e991STom Herbert t->encap.dport) ||
15274565e991STom Herbert nla_put_u16(skb, IFLA_GRE_ENCAP_FLAGS,
1528e1b2cb65STom Herbert t->encap.flags))
15294565e991STom Herbert goto nla_put_failure;
15304565e991STom Herbert
153122a59be8SPhilip Prindeville if (nla_put_u8(skb, IFLA_GRE_IGNORE_DF, t->ignore_df))
153222a59be8SPhilip Prindeville goto nla_put_failure;
153322a59be8SPhilip Prindeville
15342e15ea39SPravin B Shelar if (t->collect_md) {
15352e15ea39SPravin B Shelar if (nla_put_flag(skb, IFLA_GRE_COLLECT_METADATA))
15362e15ea39SPravin B Shelar goto nla_put_failure;
15372e15ea39SPravin B Shelar }
15382e15ea39SPravin B Shelar
1539c19e654dSHerbert Xu return 0;
1540c19e654dSHerbert Xu
1541c19e654dSHerbert Xu nla_put_failure:
1542c19e654dSHerbert Xu return -EMSGSIZE;
1543c19e654dSHerbert Xu }
1544c19e654dSHerbert Xu
erspan_fill_info(struct sk_buff * skb,const struct net_device * dev)1545ee496694SHangbin Liu static int erspan_fill_info(struct sk_buff *skb, const struct net_device *dev)
1546ee496694SHangbin Liu {
1547ee496694SHangbin Liu struct ip_tunnel *t = netdev_priv(dev);
1548ee496694SHangbin Liu
1549ee496694SHangbin Liu if (t->erspan_ver <= 2) {
1550ee496694SHangbin Liu if (t->erspan_ver != 0 && !t->collect_md)
1551ee496694SHangbin Liu t->parms.o_flags |= TUNNEL_KEY;
1552ee496694SHangbin Liu
1553ee496694SHangbin Liu if (nla_put_u8(skb, IFLA_GRE_ERSPAN_VER, t->erspan_ver))
1554ee496694SHangbin Liu goto nla_put_failure;
1555ee496694SHangbin Liu
1556ee496694SHangbin Liu if (t->erspan_ver == 1) {
1557ee496694SHangbin Liu if (nla_put_u32(skb, IFLA_GRE_ERSPAN_INDEX, t->index))
1558ee496694SHangbin Liu goto nla_put_failure;
1559ee496694SHangbin Liu } else if (t->erspan_ver == 2) {
1560ee496694SHangbin Liu if (nla_put_u8(skb, IFLA_GRE_ERSPAN_DIR, t->dir))
1561ee496694SHangbin Liu goto nla_put_failure;
1562ee496694SHangbin Liu if (nla_put_u16(skb, IFLA_GRE_ERSPAN_HWID, t->hwid))
1563ee496694SHangbin Liu goto nla_put_failure;
1564ee496694SHangbin Liu }
1565ee496694SHangbin Liu }
1566ee496694SHangbin Liu
1567ee496694SHangbin Liu return ipgre_fill_info(skb, dev);
1568ee496694SHangbin Liu
1569ee496694SHangbin Liu nla_put_failure:
1570ee496694SHangbin Liu return -EMSGSIZE;
1571ee496694SHangbin Liu }
1572ee496694SHangbin Liu
erspan_setup(struct net_device * dev)157384e54fe0SWilliam Tu static void erspan_setup(struct net_device *dev)
157484e54fe0SWilliam Tu {
157584581bdaSXin Long struct ip_tunnel *t = netdev_priv(dev);
157684581bdaSXin Long
157784e54fe0SWilliam Tu ether_setup(dev);
15780e141f75SHaishuang Yan dev->max_mtu = 0;
157984e54fe0SWilliam Tu dev->netdev_ops = &erspan_netdev_ops;
158084e54fe0SWilliam Tu dev->priv_flags &= ~IFF_TX_SKB_SHARING;
158184e54fe0SWilliam Tu dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
158284e54fe0SWilliam Tu ip_tunnel_setup(dev, erspan_net_id);
158384581bdaSXin Long t->erspan_ver = 1;
158484e54fe0SWilliam Tu }
158584e54fe0SWilliam Tu
1586c19e654dSHerbert Xu static const struct nla_policy ipgre_policy[IFLA_GRE_MAX + 1] = {
1587c19e654dSHerbert Xu [IFLA_GRE_LINK] = { .type = NLA_U32 },
1588c19e654dSHerbert Xu [IFLA_GRE_IFLAGS] = { .type = NLA_U16 },
1589c19e654dSHerbert Xu [IFLA_GRE_OFLAGS] = { .type = NLA_U16 },
1590c19e654dSHerbert Xu [IFLA_GRE_IKEY] = { .type = NLA_U32 },
1591c19e654dSHerbert Xu [IFLA_GRE_OKEY] = { .type = NLA_U32 },
1592c593642cSPankaj Bharadiya [IFLA_GRE_LOCAL] = { .len = sizeof_field(struct iphdr, saddr) },
1593c593642cSPankaj Bharadiya [IFLA_GRE_REMOTE] = { .len = sizeof_field(struct iphdr, daddr) },
1594c19e654dSHerbert Xu [IFLA_GRE_TTL] = { .type = NLA_U8 },
1595c19e654dSHerbert Xu [IFLA_GRE_TOS] = { .type = NLA_U8 },
1596c19e654dSHerbert Xu [IFLA_GRE_PMTUDISC] = { .type = NLA_U8 },
15974565e991STom Herbert [IFLA_GRE_ENCAP_TYPE] = { .type = NLA_U16 },
15984565e991STom Herbert [IFLA_GRE_ENCAP_FLAGS] = { .type = NLA_U16 },
15994565e991STom Herbert [IFLA_GRE_ENCAP_SPORT] = { .type = NLA_U16 },
16004565e991STom Herbert [IFLA_GRE_ENCAP_DPORT] = { .type = NLA_U16 },
16012e15ea39SPravin B Shelar [IFLA_GRE_COLLECT_METADATA] = { .type = NLA_FLAG },
160222a59be8SPhilip Prindeville [IFLA_GRE_IGNORE_DF] = { .type = NLA_U8 },
16039830ad4cSCraig Gallek [IFLA_GRE_FWMARK] = { .type = NLA_U32 },
160484e54fe0SWilliam Tu [IFLA_GRE_ERSPAN_INDEX] = { .type = NLA_U32 },
1605f551c91dSWilliam Tu [IFLA_GRE_ERSPAN_VER] = { .type = NLA_U8 },
1606f551c91dSWilliam Tu [IFLA_GRE_ERSPAN_DIR] = { .type = NLA_U8 },
1607f551c91dSWilliam Tu [IFLA_GRE_ERSPAN_HWID] = { .type = NLA_U16 },
1608c19e654dSHerbert Xu };
1609c19e654dSHerbert Xu
1610c19e654dSHerbert Xu static struct rtnl_link_ops ipgre_link_ops __read_mostly = {
1611c19e654dSHerbert Xu .kind = "gre",
1612c19e654dSHerbert Xu .maxtype = IFLA_GRE_MAX,
1613c19e654dSHerbert Xu .policy = ipgre_policy,
1614c19e654dSHerbert Xu .priv_size = sizeof(struct ip_tunnel),
1615c19e654dSHerbert Xu .setup = ipgre_tunnel_setup,
1616c19e654dSHerbert Xu .validate = ipgre_tunnel_validate,
1617c19e654dSHerbert Xu .newlink = ipgre_newlink,
1618c19e654dSHerbert Xu .changelink = ipgre_changelink,
1619c5441932SPravin B Shelar .dellink = ip_tunnel_dellink,
1620c19e654dSHerbert Xu .get_size = ipgre_get_size,
1621c19e654dSHerbert Xu .fill_info = ipgre_fill_info,
16221728d4faSNicolas Dichtel .get_link_net = ip_tunnel_get_link_net,
1623c19e654dSHerbert Xu };
1624c19e654dSHerbert Xu
1625e1a80002SHerbert Xu static struct rtnl_link_ops ipgre_tap_ops __read_mostly = {
1626e1a80002SHerbert Xu .kind = "gretap",
1627e1a80002SHerbert Xu .maxtype = IFLA_GRE_MAX,
1628e1a80002SHerbert Xu .policy = ipgre_policy,
1629e1a80002SHerbert Xu .priv_size = sizeof(struct ip_tunnel),
1630e1a80002SHerbert Xu .setup = ipgre_tap_setup,
1631e1a80002SHerbert Xu .validate = ipgre_tap_validate,
1632e1a80002SHerbert Xu .newlink = ipgre_newlink,
1633e1a80002SHerbert Xu .changelink = ipgre_changelink,
1634c5441932SPravin B Shelar .dellink = ip_tunnel_dellink,
1635e1a80002SHerbert Xu .get_size = ipgre_get_size,
1636e1a80002SHerbert Xu .fill_info = ipgre_fill_info,
16371728d4faSNicolas Dichtel .get_link_net = ip_tunnel_get_link_net,
1638e1a80002SHerbert Xu };
1639e1a80002SHerbert Xu
164084e54fe0SWilliam Tu static struct rtnl_link_ops erspan_link_ops __read_mostly = {
164184e54fe0SWilliam Tu .kind = "erspan",
164284e54fe0SWilliam Tu .maxtype = IFLA_GRE_MAX,
164384e54fe0SWilliam Tu .policy = ipgre_policy,
164484e54fe0SWilliam Tu .priv_size = sizeof(struct ip_tunnel),
164584e54fe0SWilliam Tu .setup = erspan_setup,
164684e54fe0SWilliam Tu .validate = erspan_validate,
1647e1f8f78fSPetr Machata .newlink = erspan_newlink,
1648e1f8f78fSPetr Machata .changelink = erspan_changelink,
164984e54fe0SWilliam Tu .dellink = ip_tunnel_dellink,
165084e54fe0SWilliam Tu .get_size = ipgre_get_size,
1651ee496694SHangbin Liu .fill_info = erspan_fill_info,
165284e54fe0SWilliam Tu .get_link_net = ip_tunnel_get_link_net,
165384e54fe0SWilliam Tu };
165484e54fe0SWilliam Tu
gretap_fb_dev_create(struct net * net,const char * name,u8 name_assign_type)1655b2acd1dcSPravin B Shelar struct net_device *gretap_fb_dev_create(struct net *net, const char *name,
1656b2acd1dcSPravin B Shelar u8 name_assign_type)
1657b2acd1dcSPravin B Shelar {
1658b2acd1dcSPravin B Shelar struct nlattr *tb[IFLA_MAX + 1];
1659b2acd1dcSPravin B Shelar struct net_device *dev;
1660106da663SNicolas Dichtel LIST_HEAD(list_kill);
1661b2acd1dcSPravin B Shelar struct ip_tunnel *t;
1662b2acd1dcSPravin B Shelar int err;
1663b2acd1dcSPravin B Shelar
1664b2acd1dcSPravin B Shelar memset(&tb, 0, sizeof(tb));
1665b2acd1dcSPravin B Shelar
1666b2acd1dcSPravin B Shelar dev = rtnl_create_link(net, name, name_assign_type,
1667d0522f1cSDavid Ahern &ipgre_tap_ops, tb, NULL);
1668b2acd1dcSPravin B Shelar if (IS_ERR(dev))
1669b2acd1dcSPravin B Shelar return dev;
1670b2acd1dcSPravin B Shelar
1671b2acd1dcSPravin B Shelar /* Configure flow based GRE device. */
1672b2acd1dcSPravin B Shelar t = netdev_priv(dev);
1673b2acd1dcSPravin B Shelar t->collect_md = true;
1674b2acd1dcSPravin B Shelar
16757a3f4a18SMatthias Schiffer err = ipgre_newlink(net, dev, tb, NULL, NULL);
1676106da663SNicolas Dichtel if (err < 0) {
1677106da663SNicolas Dichtel free_netdev(dev);
1678106da663SNicolas Dichtel return ERR_PTR(err);
1679106da663SNicolas Dichtel }
16807e059158SDavid Wragg
16817e059158SDavid Wragg /* openvswitch users expect packet sizes to be unrestricted,
16827e059158SDavid Wragg * so set the largest MTU we can.
16837e059158SDavid Wragg */
16847e059158SDavid Wragg err = __ip_tunnel_change_mtu(dev, IP_MAX_MTU, false);
16857e059158SDavid Wragg if (err)
16867e059158SDavid Wragg goto out;
16877e059158SDavid Wragg
16881d997f10SHangbin Liu err = rtnl_configure_link(dev, NULL, 0, NULL);
1689da6f1da8SNicolas Dichtel if (err < 0)
1690da6f1da8SNicolas Dichtel goto out;
1691da6f1da8SNicolas Dichtel
1692b2acd1dcSPravin B Shelar return dev;
1693b2acd1dcSPravin B Shelar out:
1694106da663SNicolas Dichtel ip_tunnel_dellink(dev, &list_kill);
1695106da663SNicolas Dichtel unregister_netdevice_many(&list_kill);
1696b2acd1dcSPravin B Shelar return ERR_PTR(err);
1697b2acd1dcSPravin B Shelar }
1698b2acd1dcSPravin B Shelar EXPORT_SYMBOL_GPL(gretap_fb_dev_create);
1699b2acd1dcSPravin B Shelar
ipgre_tap_init_net(struct net * net)1700c5441932SPravin B Shelar static int __net_init ipgre_tap_init_net(struct net *net)
1701c5441932SPravin B Shelar {
17022e15ea39SPravin B Shelar return ip_tunnel_init_net(net, gre_tap_net_id, &ipgre_tap_ops, "gretap0");
1703c5441932SPravin B Shelar }
1704c5441932SPravin B Shelar
ipgre_tap_exit_batch_net(struct list_head * list_net)170564bc1781SEric Dumazet static void __net_exit ipgre_tap_exit_batch_net(struct list_head *list_net)
1706c5441932SPravin B Shelar {
170764bc1781SEric Dumazet ip_tunnel_delete_nets(list_net, gre_tap_net_id, &ipgre_tap_ops);
1708c5441932SPravin B Shelar }
1709c5441932SPravin B Shelar
1710c5441932SPravin B Shelar static struct pernet_operations ipgre_tap_net_ops = {
1711c5441932SPravin B Shelar .init = ipgre_tap_init_net,
171264bc1781SEric Dumazet .exit_batch = ipgre_tap_exit_batch_net,
1713c5441932SPravin B Shelar .id = &gre_tap_net_id,
1714c5441932SPravin B Shelar .size = sizeof(struct ip_tunnel_net),
1715c5441932SPravin B Shelar };
17161da177e4SLinus Torvalds
erspan_init_net(struct net * net)171784e54fe0SWilliam Tu static int __net_init erspan_init_net(struct net *net)
171884e54fe0SWilliam Tu {
171984e54fe0SWilliam Tu return ip_tunnel_init_net(net, erspan_net_id,
172084e54fe0SWilliam Tu &erspan_link_ops, "erspan0");
172184e54fe0SWilliam Tu }
172284e54fe0SWilliam Tu
erspan_exit_batch_net(struct list_head * net_list)172364bc1781SEric Dumazet static void __net_exit erspan_exit_batch_net(struct list_head *net_list)
172484e54fe0SWilliam Tu {
172564bc1781SEric Dumazet ip_tunnel_delete_nets(net_list, erspan_net_id, &erspan_link_ops);
172684e54fe0SWilliam Tu }
172784e54fe0SWilliam Tu
172884e54fe0SWilliam Tu static struct pernet_operations erspan_net_ops = {
172984e54fe0SWilliam Tu .init = erspan_init_net,
173064bc1781SEric Dumazet .exit_batch = erspan_exit_batch_net,
173184e54fe0SWilliam Tu .id = &erspan_net_id,
173284e54fe0SWilliam Tu .size = sizeof(struct ip_tunnel_net),
173384e54fe0SWilliam Tu };
173484e54fe0SWilliam Tu
ipgre_init(void)17351da177e4SLinus Torvalds static int __init ipgre_init(void)
17361da177e4SLinus Torvalds {
17371da177e4SLinus Torvalds int err;
17381da177e4SLinus Torvalds
1739058bd4d2SJoe Perches pr_info("GRE over IPv4 tunneling driver\n");
17401da177e4SLinus Torvalds
1741cfb8fbf2SEric W. Biederman err = register_pernet_device(&ipgre_net_ops);
174259a4c759SPavel Emelyanov if (err < 0)
1743c2892f02SAlexey Dobriyan return err;
1744c2892f02SAlexey Dobriyan
1745c5441932SPravin B Shelar err = register_pernet_device(&ipgre_tap_net_ops);
1746c5441932SPravin B Shelar if (err < 0)
1747e3d0328cSWilliam Tu goto pnet_tap_failed;
1748c5441932SPravin B Shelar
174984e54fe0SWilliam Tu err = register_pernet_device(&erspan_net_ops);
175084e54fe0SWilliam Tu if (err < 0)
175184e54fe0SWilliam Tu goto pnet_erspan_failed;
175284e54fe0SWilliam Tu
17539f57c67cSPravin B Shelar err = gre_add_protocol(&ipgre_protocol, GREPROTO_CISCO);
1754c2892f02SAlexey Dobriyan if (err < 0) {
1755058bd4d2SJoe Perches pr_info("%s: can't add protocol\n", __func__);
1756c2892f02SAlexey Dobriyan goto add_proto_failed;
1757c2892f02SAlexey Dobriyan }
17587daa0004SPavel Emelyanov
1759c19e654dSHerbert Xu err = rtnl_link_register(&ipgre_link_ops);
1760c19e654dSHerbert Xu if (err < 0)
1761c19e654dSHerbert Xu goto rtnl_link_failed;
1762c19e654dSHerbert Xu
1763e1a80002SHerbert Xu err = rtnl_link_register(&ipgre_tap_ops);
1764e1a80002SHerbert Xu if (err < 0)
1765e1a80002SHerbert Xu goto tap_ops_failed;
1766e1a80002SHerbert Xu
176784e54fe0SWilliam Tu err = rtnl_link_register(&erspan_link_ops);
176884e54fe0SWilliam Tu if (err < 0)
176984e54fe0SWilliam Tu goto erspan_link_failed;
177084e54fe0SWilliam Tu
1771c5441932SPravin B Shelar return 0;
1772c19e654dSHerbert Xu
177384e54fe0SWilliam Tu erspan_link_failed:
177484e54fe0SWilliam Tu rtnl_link_unregister(&ipgre_tap_ops);
1775e1a80002SHerbert Xu tap_ops_failed:
1776e1a80002SHerbert Xu rtnl_link_unregister(&ipgre_link_ops);
1777c19e654dSHerbert Xu rtnl_link_failed:
17789f57c67cSPravin B Shelar gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO);
1779c2892f02SAlexey Dobriyan add_proto_failed:
178084e54fe0SWilliam Tu unregister_pernet_device(&erspan_net_ops);
178184e54fe0SWilliam Tu pnet_erspan_failed:
1782c5441932SPravin B Shelar unregister_pernet_device(&ipgre_tap_net_ops);
1783e3d0328cSWilliam Tu pnet_tap_failed:
1784c2892f02SAlexey Dobriyan unregister_pernet_device(&ipgre_net_ops);
1785c5441932SPravin B Shelar return err;
17861da177e4SLinus Torvalds }
17871da177e4SLinus Torvalds
ipgre_fini(void)1788db44575fSAlexey Kuznetsov static void __exit ipgre_fini(void)
17891da177e4SLinus Torvalds {
1790e1a80002SHerbert Xu rtnl_link_unregister(&ipgre_tap_ops);
1791c19e654dSHerbert Xu rtnl_link_unregister(&ipgre_link_ops);
179284e54fe0SWilliam Tu rtnl_link_unregister(&erspan_link_ops);
17939f57c67cSPravin B Shelar gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO);
1794c5441932SPravin B Shelar unregister_pernet_device(&ipgre_tap_net_ops);
1795c2892f02SAlexey Dobriyan unregister_pernet_device(&ipgre_net_ops);
179684e54fe0SWilliam Tu unregister_pernet_device(&erspan_net_ops);
17971da177e4SLinus Torvalds }
17981da177e4SLinus Torvalds
17991da177e4SLinus Torvalds module_init(ipgre_init);
18001da177e4SLinus Torvalds module_exit(ipgre_fini);
18011da177e4SLinus Torvalds MODULE_LICENSE("GPL");
18024d74f8baSPatrick McHardy MODULE_ALIAS_RTNL_LINK("gre");
18034d74f8baSPatrick McHardy MODULE_ALIAS_RTNL_LINK("gretap");
180484e54fe0SWilliam Tu MODULE_ALIAS_RTNL_LINK("erspan");
18058909c9adSVasiliy Kulikov MODULE_ALIAS_NETDEV("gre0");
1806c5441932SPravin B Shelar MODULE_ALIAS_NETDEV("gretap0");
180784e54fe0SWilliam Tu MODULE_ALIAS_NETDEV("erspan0");
1808