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>
47*25376a89SIdo Schimmel #include <net/inet_dscp.h>
481da177e4SLinus Torvalds
491da177e4SLinus Torvalds /*
501da177e4SLinus Torvalds Problems & solutions
511da177e4SLinus Torvalds --------------------
521da177e4SLinus Torvalds
531da177e4SLinus Torvalds 1. The most important issue is detecting local dead loops.
541da177e4SLinus Torvalds They would cause complete host lockup in transmit, which
551da177e4SLinus Torvalds would be "resolved" by stack overflow or, if queueing is enabled,
561da177e4SLinus Torvalds with infinite looping in net_bh.
571da177e4SLinus Torvalds
581da177e4SLinus Torvalds We cannot track such dead loops during route installation,
591da177e4SLinus Torvalds it is infeasible task. The most general solutions would be
601da177e4SLinus Torvalds to keep skb->encapsulation counter (sort of local ttl),
616d0722a2SEric Dumazet and silently drop packet when it expires. It is a good
62bff52857Sstephen hemminger solution, but it supposes maintaining new variable in ALL
631da177e4SLinus Torvalds skb, even if no tunneling is used.
641da177e4SLinus Torvalds
656d0722a2SEric Dumazet Current solution: xmit_recursion breaks dead loops. This is a percpu
666d0722a2SEric Dumazet counter, since when we enter the first ndo_xmit(), cpu migration is
676d0722a2SEric Dumazet forbidden. We force an exit if this counter reaches RECURSION_LIMIT
681da177e4SLinus Torvalds
691da177e4SLinus Torvalds 2. Networking dead loops would not kill routers, but would really
701da177e4SLinus Torvalds kill network. IP hop limit plays role of "t->recursion" in this case,
711da177e4SLinus Torvalds if we copy it from packet being encapsulated to upper header.
721da177e4SLinus Torvalds It is very good solution, but it introduces two problems:
731da177e4SLinus Torvalds
741da177e4SLinus Torvalds - Routing protocols, using packets with ttl=1 (OSPF, RIP2),
751da177e4SLinus Torvalds do not work over tunnels.
761da177e4SLinus Torvalds - traceroute does not work. I planned to relay ICMP from tunnel,
771da177e4SLinus Torvalds so that this problem would be solved and traceroute output
781da177e4SLinus Torvalds would even more informative. This idea appeared to be wrong:
791da177e4SLinus Torvalds only Linux complies to rfc1812 now (yes, guys, Linux is the only
801da177e4SLinus Torvalds true router now :-)), all routers (at least, in neighbourhood of mine)
811da177e4SLinus Torvalds return only 8 bytes of payload. It is the end.
821da177e4SLinus Torvalds
831da177e4SLinus Torvalds Hence, if we want that OSPF worked or traceroute said something reasonable,
841da177e4SLinus Torvalds we should search for another solution.
851da177e4SLinus Torvalds
861da177e4SLinus Torvalds One of them is to parse packet trying to detect inner encapsulation
871da177e4SLinus Torvalds made by our node. It is difficult or even impossible, especially,
88bff52857Sstephen hemminger taking into account fragmentation. TO be short, ttl is not solution at all.
891da177e4SLinus Torvalds
901da177e4SLinus Torvalds Current solution: The solution was UNEXPECTEDLY SIMPLE.
911da177e4SLinus Torvalds We force DF flag on tunnels with preconfigured hop limit,
921da177e4SLinus Torvalds that is ALL. :-) Well, it does not remove the problem completely,
931da177e4SLinus Torvalds but exponential growth of network traffic is changed to linear
941da177e4SLinus Torvalds (branches, that exceed pmtu are pruned) and tunnel mtu
95bff52857Sstephen hemminger rapidly degrades to value <68, where looping stops.
961da177e4SLinus Torvalds Yes, it is not good if there exists a router in the loop,
971da177e4SLinus Torvalds which does not force DF, even when encapsulating packets have DF set.
981da177e4SLinus Torvalds But it is not our problem! Nobody could accuse us, we made
991da177e4SLinus Torvalds all that we could make. Even if it is your gated who injected
1001da177e4SLinus Torvalds fatal route to network, even if it were you who configured
1011da177e4SLinus Torvalds fatal static route: you are innocent. :-)
1021da177e4SLinus Torvalds
1031da177e4SLinus Torvalds Alexey Kuznetsov.
1041da177e4SLinus Torvalds */
1051da177e4SLinus Torvalds
106eccc1bb8Sstephen hemminger static bool log_ecn_error = true;
107eccc1bb8Sstephen hemminger module_param(log_ecn_error, bool, 0644);
108eccc1bb8Sstephen hemminger MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN");
109eccc1bb8Sstephen hemminger
110c19e654dSHerbert Xu static struct rtnl_link_ops ipgre_link_ops __read_mostly;
111aab1e898SGuillaume Nault static const struct header_ops ipgre_header_ops;
112aab1e898SGuillaume Nault
1131da177e4SLinus Torvalds static int ipgre_tunnel_init(struct net_device *dev);
1141a66a836SWilliam Tu static void erspan_build_header(struct sk_buff *skb,
115c69de58bSWilliam Tu u32 id, u32 index,
116a3222dc9SWilliam Tu bool truncate, bool is_ipv4);
117eb8ce741SPavel Emelyanov
118c7d03a00SAlexey Dobriyan static unsigned int ipgre_net_id __read_mostly;
119c7d03a00SAlexey Dobriyan static unsigned int gre_tap_net_id __read_mostly;
12084e54fe0SWilliam Tu static unsigned int erspan_net_id __read_mostly;
121eb8ce741SPavel Emelyanov
ipgre_err(struct sk_buff * skb,u32 info,const struct tnl_ptk_info * tpi)12232bbd879SStefano Brivio static int ipgre_err(struct sk_buff *skb, u32 info,
123bda7bb46SPravin B Shelar const struct tnl_ptk_info *tpi)
1241da177e4SLinus Torvalds {
1251da177e4SLinus Torvalds
126071f92d0SRami Rosen /* All the routers (except for Linux) return only
1271da177e4SLinus Torvalds 8 bytes of packet payload. It means, that precise relaying of
1281da177e4SLinus Torvalds ICMP in the real Internet is absolutely infeasible.
1291da177e4SLinus Torvalds
1301da177e4SLinus Torvalds Moreover, Cisco "wise men" put GRE key to the third word
131c5441932SPravin B Shelar in GRE header. It makes impossible maintaining even soft
132c5441932SPravin B Shelar state for keyed GRE tunnels with enabled checksum. Tell
133c5441932SPravin B Shelar them "thank you".
1341da177e4SLinus Torvalds
1351da177e4SLinus Torvalds Well, I wonder, rfc1812 was written by Cisco employee,
136bff52857Sstephen hemminger what the hell these idiots break standards established
137bff52857Sstephen hemminger by themselves???
1381da177e4SLinus Torvalds */
139c5441932SPravin B Shelar struct net *net = dev_net(skb->dev);
140c5441932SPravin B Shelar struct ip_tunnel_net *itn;
14196f5a846SEric Dumazet const struct iphdr *iph;
14288c7664fSArnaldo Carvalho de Melo const int type = icmp_hdr(skb)->type;
14388c7664fSArnaldo Carvalho de Melo const int code = icmp_hdr(skb)->code;
14420e1954fSEric Dumazet unsigned int data_len = 0;
1451da177e4SLinus Torvalds struct ip_tunnel *t;
146d2083287Sstephen hemminger
147bda7bb46SPravin B Shelar if (tpi->proto == htons(ETH_P_TEB))
148c5441932SPravin B Shelar itn = net_generic(net, gre_tap_net_id);
14951dc63e3SHaishuang Yan else if (tpi->proto == htons(ETH_P_ERSPAN) ||
15051dc63e3SHaishuang Yan tpi->proto == htons(ETH_P_ERSPAN2))
15151dc63e3SHaishuang Yan itn = net_generic(net, erspan_net_id);
152c5441932SPravin B Shelar else
153c5441932SPravin B Shelar itn = net_generic(net, ipgre_net_id);
154c5441932SPravin B Shelar
155c0c0c50fSDuan Jiong iph = (const struct iphdr *)(icmp_hdr(skb) + 1);
156bda7bb46SPravin B Shelar t = ip_tunnel_lookup(itn, skb->dev->ifindex, tpi->flags,
157bda7bb46SPravin B Shelar iph->daddr, iph->saddr, tpi->key);
158d2083287Sstephen hemminger
15951456b29SIan Morris if (!t)
16032bbd879SStefano Brivio return -ENOENT;
16132bbd879SStefano Brivio
16232bbd879SStefano Brivio switch (type) {
16332bbd879SStefano Brivio default:
16432bbd879SStefano Brivio case ICMP_PARAMETERPROB:
16532bbd879SStefano Brivio return 0;
16632bbd879SStefano Brivio
16732bbd879SStefano Brivio case ICMP_DEST_UNREACH:
16832bbd879SStefano Brivio switch (code) {
16932bbd879SStefano Brivio case ICMP_SR_FAILED:
17032bbd879SStefano Brivio case ICMP_PORT_UNREACH:
17132bbd879SStefano Brivio /* Impossible event. */
17232bbd879SStefano Brivio return 0;
17332bbd879SStefano Brivio default:
17432bbd879SStefano Brivio /* All others are translated to HOST_UNREACH.
17532bbd879SStefano Brivio rfc2003 contains "deep thoughts" about NET_UNREACH,
17632bbd879SStefano Brivio I believe they are just ether pollution. --ANK
17732bbd879SStefano Brivio */
17832bbd879SStefano Brivio break;
17932bbd879SStefano Brivio }
18032bbd879SStefano Brivio break;
18132bbd879SStefano Brivio
18232bbd879SStefano Brivio case ICMP_TIME_EXCEEDED:
18332bbd879SStefano Brivio if (code != ICMP_EXC_TTL)
18432bbd879SStefano Brivio return 0;
18532bbd879SStefano Brivio data_len = icmp_hdr(skb)->un.reserved[1] * 4; /* RFC 4884 4.1 */
18632bbd879SStefano Brivio break;
18732bbd879SStefano Brivio
18832bbd879SStefano Brivio case ICMP_REDIRECT:
18932bbd879SStefano Brivio break;
19032bbd879SStefano Brivio }
19136393395SDavid S. Miller
1929b8c6d7bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6)
1939b8c6d7bSEric Dumazet if (tpi->proto == htons(ETH_P_IPV6) &&
19420e1954fSEric Dumazet !ip6_err_gen_icmpv6_unreach(skb, iph->ihl * 4 + tpi->hdr_len,
19520e1954fSEric Dumazet type, data_len))
19632bbd879SStefano Brivio return 0;
1979b8c6d7bSEric Dumazet #endif
1989b8c6d7bSEric Dumazet
19936393395SDavid S. Miller if (t->parms.iph.daddr == 0 ||
200f97c1e0cSJoe Perches ipv4_is_multicast(t->parms.iph.daddr))
20132bbd879SStefano Brivio return 0;
2021da177e4SLinus Torvalds
2031da177e4SLinus Torvalds if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED)
20432bbd879SStefano Brivio return 0;
2051da177e4SLinus Torvalds
206da6185d8SWei Yongjun if (time_before(jiffies, t->err_time + IPTUNNEL_ERR_TIMEO))
2071da177e4SLinus Torvalds t->err_count++;
2081da177e4SLinus Torvalds else
2091da177e4SLinus Torvalds t->err_count = 1;
2101da177e4SLinus Torvalds t->err_time = jiffies;
21132bbd879SStefano Brivio
21232bbd879SStefano Brivio return 0;
2139f57c67cSPravin B Shelar }
2149f57c67cSPravin B Shelar
gre_err(struct sk_buff * skb,u32 info)2159f57c67cSPravin B Shelar static void gre_err(struct sk_buff *skb, u32 info)
2169f57c67cSPravin B Shelar {
2179f57c67cSPravin B Shelar /* All the routers (except for Linux) return only
2189f57c67cSPravin B Shelar * 8 bytes of packet payload. It means, that precise relaying of
2199f57c67cSPravin B Shelar * ICMP in the real Internet is absolutely infeasible.
2209f57c67cSPravin B Shelar *
2219f57c67cSPravin B Shelar * Moreover, Cisco "wise men" put GRE key to the third word
2229f57c67cSPravin B Shelar * in GRE header. It makes impossible maintaining even soft
2239f57c67cSPravin B Shelar * state for keyed
2249f57c67cSPravin B Shelar * GRE tunnels with enabled checksum. Tell them "thank you".
2259f57c67cSPravin B Shelar *
2269f57c67cSPravin B Shelar * Well, I wonder, rfc1812 was written by Cisco employee,
2279f57c67cSPravin B Shelar * what the hell these idiots break standards established
2289f57c67cSPravin B Shelar * by themselves???
2299f57c67cSPravin B Shelar */
2309f57c67cSPravin B Shelar
231e582615aSEric Dumazet const struct iphdr *iph = (struct iphdr *)skb->data;
2329f57c67cSPravin B Shelar const int type = icmp_hdr(skb)->type;
2339f57c67cSPravin B Shelar const int code = icmp_hdr(skb)->code;
2349f57c67cSPravin B Shelar struct tnl_ptk_info tpi;
2359f57c67cSPravin B Shelar
236b0350d51SHaishuang Yan if (gre_parse_header(skb, &tpi, NULL, htons(ETH_P_IP),
237b0350d51SHaishuang Yan iph->ihl * 4) < 0)
2389f57c67cSPravin B Shelar return;
2399f57c67cSPravin B Shelar
2409f57c67cSPravin B Shelar if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) {
2419f57c67cSPravin B Shelar ipv4_update_pmtu(skb, dev_net(skb->dev), info,
242d888f396SMaciej Żenczykowski skb->dev->ifindex, IPPROTO_GRE);
2439f57c67cSPravin B Shelar return;
2449f57c67cSPravin B Shelar }
2459f57c67cSPravin B Shelar if (type == ICMP_REDIRECT) {
2461042caa7SMaciej Żenczykowski ipv4_redirect(skb, dev_net(skb->dev), skb->dev->ifindex,
2471042caa7SMaciej Żenczykowski IPPROTO_GRE);
2489f57c67cSPravin B Shelar return;
2499f57c67cSPravin B Shelar }
2509f57c67cSPravin B Shelar
2519f57c67cSPravin B Shelar ipgre_err(skb, info, &tpi);
2521da177e4SLinus Torvalds }
2531da177e4SLinus Torvalds
is_erspan_type1(int gre_hdr_len)254f989d546SWilliam Tu static bool is_erspan_type1(int gre_hdr_len)
255f989d546SWilliam Tu {
256f989d546SWilliam Tu /* Both ERSPAN type I (version 0) and type II (version 1) use
257f989d546SWilliam Tu * protocol 0x88BE, but the type I has only 4-byte GRE header,
258f989d546SWilliam Tu * while type II has 8-byte.
259f989d546SWilliam Tu */
260f989d546SWilliam Tu return gre_hdr_len == 4;
261f989d546SWilliam Tu }
262f989d546SWilliam Tu
erspan_rcv(struct sk_buff * skb,struct tnl_ptk_info * tpi,int gre_hdr_len)26384e54fe0SWilliam Tu static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi,
26484e54fe0SWilliam Tu int gre_hdr_len)
26584e54fe0SWilliam Tu {
26684e54fe0SWilliam Tu struct net *net = dev_net(skb->dev);
26784e54fe0SWilliam Tu struct metadata_dst *tun_dst = NULL;
2681d7e2ed2SWilliam Tu struct erspan_base_hdr *ershdr;
2695832c4a7SAlexander Lobakin IP_TUNNEL_DECLARE_FLAGS(flags);
27084e54fe0SWilliam Tu struct ip_tunnel_net *itn;
27184e54fe0SWilliam Tu struct ip_tunnel *tunnel;
27284e54fe0SWilliam Tu const struct iphdr *iph;
2733df19283SWilliam Tu struct erspan_md2 *md2;
2741d7e2ed2SWilliam Tu int ver;
27584e54fe0SWilliam Tu int len;
27684e54fe0SWilliam Tu
2775832c4a7SAlexander Lobakin ip_tunnel_flags_copy(flags, tpi->flags);
2785832c4a7SAlexander Lobakin
27984e54fe0SWilliam Tu itn = net_generic(net, erspan_net_id);
28084e54fe0SWilliam Tu iph = ip_hdr(skb);
281f989d546SWilliam Tu if (is_erspan_type1(gre_hdr_len)) {
282f989d546SWilliam Tu ver = 0;
2835832c4a7SAlexander Lobakin __set_bit(IP_TUNNEL_NO_KEY_BIT, flags);
2845832c4a7SAlexander Lobakin tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, flags,
285f989d546SWilliam Tu iph->saddr, iph->daddr, 0);
286f989d546SWilliam Tu } else {
28717af4205SEric Dumazet if (unlikely(!pskb_may_pull(skb,
28817af4205SEric Dumazet gre_hdr_len + sizeof(*ershdr))))
28917af4205SEric Dumazet return PACKET_REJECT;
29017af4205SEric Dumazet
2911d7e2ed2SWilliam Tu ershdr = (struct erspan_base_hdr *)(skb->data + gre_hdr_len);
292c69de58bSWilliam Tu ver = ershdr->ver;
29317af4205SEric Dumazet iph = ip_hdr(skb);
2945832c4a7SAlexander Lobakin __set_bit(IP_TUNNEL_KEY_BIT, flags);
2955832c4a7SAlexander Lobakin tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, flags,
29684e54fe0SWilliam Tu iph->saddr, iph->daddr, tpi->key);
297f989d546SWilliam Tu }
29884e54fe0SWilliam Tu
29984e54fe0SWilliam Tu if (tunnel) {
300f989d546SWilliam Tu if (is_erspan_type1(gre_hdr_len))
301f989d546SWilliam Tu len = gre_hdr_len;
302f989d546SWilliam Tu else
3031d7e2ed2SWilliam Tu len = gre_hdr_len + erspan_hdr_len(ver);
304f989d546SWilliam Tu
3051d7e2ed2SWilliam Tu if (unlikely(!pskb_may_pull(skb, len)))
306ae3e1337SWilliam Tu return PACKET_REJECT;
3071d7e2ed2SWilliam Tu
30884e54fe0SWilliam Tu if (__iptunnel_pull_header(skb,
3091d7e2ed2SWilliam Tu len,
31084e54fe0SWilliam Tu htons(ETH_P_TEB),
31184e54fe0SWilliam Tu false, false) < 0)
31284e54fe0SWilliam Tu goto drop;
31384e54fe0SWilliam Tu
3141a66a836SWilliam Tu if (tunnel->collect_md) {
315492b67e2SLorenzo Bianconi struct erspan_metadata *pkt_md, *md;
3161a66a836SWilliam Tu struct ip_tunnel_info *info;
317492b67e2SLorenzo Bianconi unsigned char *gh;
3181a66a836SWilliam Tu __be64 tun_id;
3191a66a836SWilliam Tu
3205832c4a7SAlexander Lobakin __set_bit(IP_TUNNEL_KEY_BIT, tpi->flags);
3215832c4a7SAlexander Lobakin ip_tunnel_flags_copy(flags, tpi->flags);
3221a66a836SWilliam Tu tun_id = key32_to_tunnel_id(tpi->key);
3231a66a836SWilliam Tu
3241a66a836SWilliam Tu tun_dst = ip_tun_rx_dst(skb, flags,
3251a66a836SWilliam Tu tun_id, sizeof(*md));
3261a66a836SWilliam Tu if (!tun_dst)
3271a66a836SWilliam Tu return PACKET_REJECT;
3281a66a836SWilliam Tu
329492b67e2SLorenzo Bianconi /* skb can be uncloned in __iptunnel_pull_header, so
330492b67e2SLorenzo Bianconi * old pkt_md is no longer valid and we need to reset
331492b67e2SLorenzo Bianconi * it
332492b67e2SLorenzo Bianconi */
333492b67e2SLorenzo Bianconi gh = skb_network_header(skb) +
334492b67e2SLorenzo Bianconi skb_network_header_len(skb);
335492b67e2SLorenzo Bianconi pkt_md = (struct erspan_metadata *)(gh + gre_hdr_len +
336492b67e2SLorenzo Bianconi sizeof(*ershdr));
3371a66a836SWilliam Tu md = ip_tunnel_info_opts(&tun_dst->u.tun_info);
338f551c91dSWilliam Tu md->version = ver;
3393df19283SWilliam Tu md2 = &md->u.md2;
3403df19283SWilliam Tu memcpy(md2, pkt_md, ver == 1 ? ERSPAN_V1_MDSIZE :
3413df19283SWilliam Tu ERSPAN_V2_MDSIZE);
342f551c91dSWilliam Tu
3431a66a836SWilliam Tu info = &tun_dst->u.tun_info;
3445832c4a7SAlexander Lobakin __set_bit(IP_TUNNEL_ERSPAN_OPT_BIT,
3455832c4a7SAlexander Lobakin info->key.tun_flags);
3461a66a836SWilliam Tu info->options_len = sizeof(*md);
3471a66a836SWilliam Tu }
3481a66a836SWilliam Tu
34984e54fe0SWilliam Tu skb_reset_mac_header(skb);
35084e54fe0SWilliam Tu ip_tunnel_rcv(tunnel, skb, tpi, tun_dst, log_ecn_error);
35184e54fe0SWilliam Tu return PACKET_RCVD;
35284e54fe0SWilliam Tu }
3535a64506bSHaishuang Yan return PACKET_REJECT;
3545a64506bSHaishuang Yan
35584e54fe0SWilliam Tu drop:
35684e54fe0SWilliam Tu kfree_skb(skb);
35784e54fe0SWilliam Tu return PACKET_RCVD;
35884e54fe0SWilliam Tu }
35984e54fe0SWilliam Tu
__ipgre_rcv(struct sk_buff * skb,const struct tnl_ptk_info * tpi,struct ip_tunnel_net * itn,int hdr_len,bool raw_proto)360125372faSJiri Benc static int __ipgre_rcv(struct sk_buff *skb, const struct tnl_ptk_info *tpi,
361125372faSJiri Benc struct ip_tunnel_net *itn, int hdr_len, bool raw_proto)
3621da177e4SLinus Torvalds {
3632e15ea39SPravin B Shelar struct metadata_dst *tun_dst = NULL;
364b71d1d42SEric Dumazet const struct iphdr *iph;
3651da177e4SLinus Torvalds struct ip_tunnel *tunnel;
3661da177e4SLinus Torvalds
367eddc9ec5SArnaldo Carvalho de Melo iph = ip_hdr(skb);
368bda7bb46SPravin B Shelar tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, tpi->flags,
369bda7bb46SPravin B Shelar iph->saddr, iph->daddr, tpi->key);
3701da177e4SLinus Torvalds
371d2083287Sstephen hemminger if (tunnel) {
372c0d59da7Swenxu const struct iphdr *tnl_params;
373c0d59da7Swenxu
374125372faSJiri Benc if (__iptunnel_pull_header(skb, hdr_len, tpi->proto,
375125372faSJiri Benc raw_proto, false) < 0)
376244a797bSJiri Benc goto drop;
377244a797bSJiri Benc
378aab1e898SGuillaume Nault /* Special case for ipgre_header_parse(), which expects the
379aab1e898SGuillaume Nault * mac_header to point to the outer IP header.
380aab1e898SGuillaume Nault */
381aab1e898SGuillaume Nault if (tunnel->dev->header_ops == &ipgre_header_ops)
3820e3da5bbSTimo Teräs skb_pop_mac_header(skb);
383e271c7b4SJiri Benc else
384e271c7b4SJiri Benc skb_reset_mac_header(skb);
385c0d59da7Swenxu
386c0d59da7Swenxu tnl_params = &tunnel->parms.iph;
387c0d59da7Swenxu if (tunnel->collect_md || tnl_params->daddr == 0) {
3885832c4a7SAlexander Lobakin IP_TUNNEL_DECLARE_FLAGS(flags) = { };
389c29a70d2SPravin B Shelar __be64 tun_id;
3902e15ea39SPravin B Shelar
3915832c4a7SAlexander Lobakin __set_bit(IP_TUNNEL_CSUM_BIT, flags);
3925832c4a7SAlexander Lobakin __set_bit(IP_TUNNEL_KEY_BIT, flags);
3935832c4a7SAlexander Lobakin ip_tunnel_flags_and(flags, tpi->flags, flags);
3945832c4a7SAlexander Lobakin
395d817f432SAmir Vadai tun_id = key32_to_tunnel_id(tpi->key);
396c29a70d2SPravin B Shelar tun_dst = ip_tun_rx_dst(skb, flags, tun_id, 0);
3972e15ea39SPravin B Shelar if (!tun_dst)
3982e15ea39SPravin B Shelar return PACKET_REJECT;
3992e15ea39SPravin B Shelar }
4002e15ea39SPravin B Shelar
4012e15ea39SPravin B Shelar ip_tunnel_rcv(tunnel, skb, tpi, tun_dst, log_ecn_error);
402bda7bb46SPravin B Shelar return PACKET_RCVD;
4031da177e4SLinus Torvalds }
404125372faSJiri Benc return PACKET_NEXT;
405244a797bSJiri Benc
406244a797bSJiri Benc drop:
407244a797bSJiri Benc kfree_skb(skb);
408244a797bSJiri Benc return PACKET_RCVD;
4091da177e4SLinus Torvalds }
4101da177e4SLinus Torvalds
ipgre_rcv(struct sk_buff * skb,const struct tnl_ptk_info * tpi,int hdr_len)411125372faSJiri Benc static int ipgre_rcv(struct sk_buff *skb, const struct tnl_ptk_info *tpi,
412125372faSJiri Benc int hdr_len)
413125372faSJiri Benc {
414125372faSJiri Benc struct net *net = dev_net(skb->dev);
415125372faSJiri Benc struct ip_tunnel_net *itn;
416125372faSJiri Benc int res;
417125372faSJiri Benc
418125372faSJiri Benc if (tpi->proto == htons(ETH_P_TEB))
419125372faSJiri Benc itn = net_generic(net, gre_tap_net_id);
420125372faSJiri Benc else
421125372faSJiri Benc itn = net_generic(net, ipgre_net_id);
422125372faSJiri Benc
423125372faSJiri Benc res = __ipgre_rcv(skb, tpi, itn, hdr_len, false);
424125372faSJiri Benc if (res == PACKET_NEXT && tpi->proto == htons(ETH_P_TEB)) {
425125372faSJiri Benc /* ipgre tunnels in collect metadata mode should receive
426125372faSJiri Benc * also ETH_P_TEB traffic.
427125372faSJiri Benc */
428125372faSJiri Benc itn = net_generic(net, ipgre_net_id);
429125372faSJiri Benc res = __ipgre_rcv(skb, tpi, itn, hdr_len, true);
430125372faSJiri Benc }
431125372faSJiri Benc return res;
432125372faSJiri Benc }
433125372faSJiri Benc
gre_rcv(struct sk_buff * skb)4349f57c67cSPravin B Shelar static int gre_rcv(struct sk_buff *skb)
4359f57c67cSPravin B Shelar {
4369f57c67cSPravin B Shelar struct tnl_ptk_info tpi;
4379f57c67cSPravin B Shelar bool csum_err = false;
43895f5c64cSTom Herbert int hdr_len;
4399f57c67cSPravin B Shelar
4409f57c67cSPravin B Shelar #ifdef CONFIG_NET_IPGRE_BROADCAST
4419f57c67cSPravin B Shelar if (ipv4_is_multicast(ip_hdr(skb)->daddr)) {
4429f57c67cSPravin B Shelar /* Looped back packet, drop it! */
4439f57c67cSPravin B Shelar if (rt_is_output_route(skb_rtable(skb)))
4449f57c67cSPravin B Shelar goto drop;
4459f57c67cSPravin B Shelar }
4469f57c67cSPravin B Shelar #endif
4479f57c67cSPravin B Shelar
448e582615aSEric Dumazet hdr_len = gre_parse_header(skb, &tpi, &csum_err, htons(ETH_P_IP), 0);
449f132ae7cSJiri Benc if (hdr_len < 0)
45095f5c64cSTom Herbert goto drop;
45195f5c64cSTom Herbert
452f551c91dSWilliam Tu if (unlikely(tpi.proto == htons(ETH_P_ERSPAN) ||
453f551c91dSWilliam Tu tpi.proto == htons(ETH_P_ERSPAN2))) {
45484e54fe0SWilliam Tu if (erspan_rcv(skb, &tpi, hdr_len) == PACKET_RCVD)
45584e54fe0SWilliam Tu return 0;
456dd8d5b8cSHaishuang Yan goto out;
45784e54fe0SWilliam Tu }
45884e54fe0SWilliam Tu
459244a797bSJiri Benc if (ipgre_rcv(skb, &tpi, hdr_len) == PACKET_RCVD)
4609f57c67cSPravin B Shelar return 0;
4619f57c67cSPravin B Shelar
462dd8d5b8cSHaishuang Yan out:
4639f57c67cSPravin B Shelar icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
4649f57c67cSPravin B Shelar drop:
4659f57c67cSPravin B Shelar kfree_skb(skb);
4669f57c67cSPravin B Shelar return 0;
4679f57c67cSPravin B Shelar }
4689f57c67cSPravin B Shelar
__gre_xmit(struct sk_buff * skb,struct net_device * dev,const struct iphdr * tnl_params,__be16 proto)469c5441932SPravin B Shelar static void __gre_xmit(struct sk_buff *skb, struct net_device *dev,
470c5441932SPravin B Shelar const struct iphdr *tnl_params,
471c5441932SPravin B Shelar __be16 proto)
472c5441932SPravin B Shelar {
473c5441932SPravin B Shelar struct ip_tunnel *tunnel = netdev_priv(dev);
4745832c4a7SAlexander Lobakin IP_TUNNEL_DECLARE_FLAGS(flags);
4755832c4a7SAlexander Lobakin
4765832c4a7SAlexander Lobakin ip_tunnel_flags_copy(flags, tunnel->parms.o_flags);
477cef401deSEric Dumazet
478c5441932SPravin B Shelar /* Push GRE header. */
479182a352dSTom Herbert gre_build_header(skb, tunnel->tun_hlen,
480ff827bebSPeilin Ye flags, proto, tunnel->parms.o_key,
4815832c4a7SAlexander Lobakin test_bit(IP_TUNNEL_SEQ_BIT, flags) ?
4825832c4a7SAlexander Lobakin htonl(atomic_fetch_inc(&tunnel->o_seqno)) : 0);
4831da177e4SLinus Torvalds
484bf3d6a8fSNicolas Dichtel ip_tunnel_xmit(skb, dev, tnl_params, tnl_params->protocol);
4851da177e4SLinus Torvalds }
4861da177e4SLinus Torvalds
gre_handle_offloads(struct sk_buff * skb,bool csum)487aed069dfSAlexander Duyck static int gre_handle_offloads(struct sk_buff *skb, bool csum)
488b2acd1dcSPravin B Shelar {
4896fa79666SEdward Cree return iptunnel_handle_offloads(skb, csum ? SKB_GSO_GRE_CSUM : SKB_GSO_GRE);
490b2acd1dcSPravin B Shelar }
491b2acd1dcSPravin B Shelar
gre_fb_xmit(struct sk_buff * skb,struct net_device * dev,__be16 proto)492862a03c3SWilliam Tu static void gre_fb_xmit(struct sk_buff *skb, struct net_device *dev,
493862a03c3SWilliam Tu __be16 proto)
494862a03c3SWilliam Tu {
49577a5196aSWilliam Tu struct ip_tunnel *tunnel = netdev_priv(dev);
4965832c4a7SAlexander Lobakin IP_TUNNEL_DECLARE_FLAGS(flags) = { };
497862a03c3SWilliam Tu struct ip_tunnel_info *tun_info;
498862a03c3SWilliam Tu const struct ip_tunnel_key *key;
499862a03c3SWilliam Tu int tunnel_hlen;
500862a03c3SWilliam Tu
501862a03c3SWilliam Tu tun_info = skb_tunnel_info(skb);
502862a03c3SWilliam Tu if (unlikely(!tun_info || !(tun_info->mode & IP_TUNNEL_INFO_TX) ||
503862a03c3SWilliam Tu ip_tunnel_info_af(tun_info) != AF_INET))
504862a03c3SWilliam Tu goto err_free_skb;
505862a03c3SWilliam Tu
506862a03c3SWilliam Tu key = &tun_info->key;
507862a03c3SWilliam Tu tunnel_hlen = gre_calc_hlen(key->tun_flags);
508862a03c3SWilliam Tu
509962924faSwenxu if (skb_cow_head(skb, dev->needed_headroom))
510962924faSwenxu goto err_free_skb;
5112e15ea39SPravin B Shelar
5122e15ea39SPravin B Shelar /* Push Tunnel header. */
5135832c4a7SAlexander Lobakin if (gre_handle_offloads(skb, test_bit(IP_TUNNEL_CSUM_BIT,
5145832c4a7SAlexander Lobakin tunnel->parms.o_flags)))
515962924faSwenxu goto err_free_skb;
5162e15ea39SPravin B Shelar
5175832c4a7SAlexander Lobakin __set_bit(IP_TUNNEL_CSUM_BIT, flags);
5185832c4a7SAlexander Lobakin __set_bit(IP_TUNNEL_KEY_BIT, flags);
5195832c4a7SAlexander Lobakin __set_bit(IP_TUNNEL_SEQ_BIT, flags);
5205832c4a7SAlexander Lobakin ip_tunnel_flags_and(flags, tun_info->key.tun_flags, flags);
5215832c4a7SAlexander Lobakin
522cba65321SDavid S. Miller gre_build_header(skb, tunnel_hlen, flags, proto,
52377a5196aSWilliam Tu tunnel_id_to_key32(tun_info->key.tun_id),
5245832c4a7SAlexander Lobakin test_bit(IP_TUNNEL_SEQ_BIT, flags) ?
5255832c4a7SAlexander Lobakin htonl(atomic_fetch_inc(&tunnel->o_seqno)) : 0);
5262e15ea39SPravin B Shelar
527962924faSwenxu ip_md_tunnel_xmit(skb, dev, IPPROTO_GRE, tunnel_hlen);
528039f5062SPravin B Shelar
5292e15ea39SPravin B Shelar return;
5302e15ea39SPravin B Shelar
5312e15ea39SPravin B Shelar err_free_skb:
5322e15ea39SPravin B Shelar kfree_skb(skb);
533c4794d22SEric Dumazet DEV_STATS_INC(dev, tx_dropped);
5342e15ea39SPravin B Shelar }
5352e15ea39SPravin B Shelar
erspan_fb_xmit(struct sk_buff * skb,struct net_device * dev)53620704bd1SXin Long static void erspan_fb_xmit(struct sk_buff *skb, struct net_device *dev)
5371a66a836SWilliam Tu {
5381a66a836SWilliam Tu struct ip_tunnel *tunnel = netdev_priv(dev);
5395832c4a7SAlexander Lobakin IP_TUNNEL_DECLARE_FLAGS(flags) = { };
5401a66a836SWilliam Tu struct ip_tunnel_info *tun_info;
5411a66a836SWilliam Tu const struct ip_tunnel_key *key;
5421a66a836SWilliam Tu struct erspan_metadata *md;
5431a66a836SWilliam Tu bool truncate = false;
544962924faSwenxu __be16 proto;
5451a66a836SWilliam Tu int tunnel_hlen;
546f551c91dSWilliam Tu int version;
5471baf5ebfSWilliam Tu int nhoff;
5481a66a836SWilliam Tu
5491a66a836SWilliam Tu tun_info = skb_tunnel_info(skb);
5501a66a836SWilliam Tu if (unlikely(!tun_info || !(tun_info->mode & IP_TUNNEL_INFO_TX) ||
5511a66a836SWilliam Tu ip_tunnel_info_af(tun_info) != AF_INET))
5521a66a836SWilliam Tu goto err_free_skb;
5531a66a836SWilliam Tu
5541a66a836SWilliam Tu key = &tun_info->key;
5555832c4a7SAlexander Lobakin if (!test_bit(IP_TUNNEL_ERSPAN_OPT_BIT, tun_info->key.tun_flags))
556962924faSwenxu goto err_free_skb;
5572eb8d6d2SXin Long if (tun_info->options_len < sizeof(*md))
558962924faSwenxu goto err_free_skb;
5592eb8d6d2SXin Long md = ip_tunnel_info_opts(tun_info);
5601a66a836SWilliam Tu
5611a66a836SWilliam Tu /* ERSPAN has fixed 8 byte GRE header */
562f551c91dSWilliam Tu version = md->version;
563f551c91dSWilliam Tu tunnel_hlen = 8 + erspan_hdr_len(version);
5641a66a836SWilliam Tu
565962924faSwenxu if (skb_cow_head(skb, dev->needed_headroom))
566962924faSwenxu goto err_free_skb;
5671a66a836SWilliam Tu
5681a66a836SWilliam Tu if (gre_handle_offloads(skb, false))
569962924faSwenxu goto err_free_skb;
5701a66a836SWilliam Tu
571f192970dSWilliam Tu if (skb->len > dev->mtu + dev->hard_header_len) {
57202d84f3eSYuanjun Gong if (pskb_trim(skb, dev->mtu + dev->hard_header_len))
57302d84f3eSYuanjun Gong goto err_free_skb;
5741a66a836SWilliam Tu truncate = true;
5751a66a836SWilliam Tu }
5761a66a836SWilliam Tu
5778e50ed77SEric Dumazet nhoff = skb_network_offset(skb);
5781baf5ebfSWilliam Tu if (skb->protocol == htons(ETH_P_IP) &&
5791baf5ebfSWilliam Tu (ntohs(ip_hdr(skb)->tot_len) > skb->len - nhoff))
5801baf5ebfSWilliam Tu truncate = true;
5811baf5ebfSWilliam Tu
582301bd140SEric Dumazet if (skb->protocol == htons(ETH_P_IPV6)) {
583301bd140SEric Dumazet int thoff;
584301bd140SEric Dumazet
585301bd140SEric Dumazet if (skb_transport_header_was_set(skb))
5868e50ed77SEric Dumazet thoff = skb_transport_offset(skb);
587301bd140SEric Dumazet else
588301bd140SEric Dumazet thoff = nhoff + sizeof(struct ipv6hdr);
589301bd140SEric Dumazet if (ntohs(ipv6_hdr(skb)->payload_len) > skb->len - thoff)
590d5db21a3SWilliam Tu truncate = true;
591301bd140SEric Dumazet }
592d5db21a3SWilliam Tu
593f551c91dSWilliam Tu if (version == 1) {
594c69de58bSWilliam Tu erspan_build_header(skb, ntohl(tunnel_id_to_key32(key->tun_id)),
5951d7e2ed2SWilliam Tu ntohl(md->u.index), truncate, true);
59620704bd1SXin Long proto = htons(ETH_P_ERSPAN);
597f551c91dSWilliam Tu } else if (version == 2) {
598c69de58bSWilliam Tu erspan_build_header_v2(skb,
599c69de58bSWilliam Tu ntohl(tunnel_id_to_key32(key->tun_id)),
600c69de58bSWilliam Tu md->u.md2.dir,
601c69de58bSWilliam Tu get_hwid(&md->u.md2),
602c69de58bSWilliam Tu truncate, true);
60320704bd1SXin Long proto = htons(ETH_P_ERSPAN2);
604f551c91dSWilliam Tu } else {
605962924faSwenxu goto err_free_skb;
606f551c91dSWilliam Tu }
6071a66a836SWilliam Tu
6085832c4a7SAlexander Lobakin __set_bit(IP_TUNNEL_SEQ_BIT, flags);
6095832c4a7SAlexander Lobakin gre_build_header(skb, 8, flags, proto, 0,
6105832c4a7SAlexander Lobakin htonl(atomic_fetch_inc(&tunnel->o_seqno)));
6111a66a836SWilliam Tu
612962924faSwenxu ip_md_tunnel_xmit(skb, dev, IPPROTO_GRE, tunnel_hlen);
6131a66a836SWilliam Tu
6141a66a836SWilliam Tu return;
6151a66a836SWilliam Tu
6161a66a836SWilliam Tu err_free_skb:
6171a66a836SWilliam Tu kfree_skb(skb);
618c4794d22SEric Dumazet DEV_STATS_INC(dev, tx_dropped);
6191a66a836SWilliam Tu }
6201a66a836SWilliam Tu
gre_fill_metadata_dst(struct net_device * dev,struct sk_buff * skb)621fc4099f1SPravin B Shelar static int gre_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
622fc4099f1SPravin B Shelar {
623fc4099f1SPravin B Shelar struct ip_tunnel_info *info = skb_tunnel_info(skb);
624962924faSwenxu const struct ip_tunnel_key *key;
625fc4099f1SPravin B Shelar struct rtable *rt;
626fc4099f1SPravin B Shelar struct flowi4 fl4;
627fc4099f1SPravin B Shelar
628fc4099f1SPravin B Shelar if (ip_tunnel_info_af(info) != AF_INET)
629fc4099f1SPravin B Shelar return -EINVAL;
630fc4099f1SPravin B Shelar
631962924faSwenxu key = &info->key;
632962924faSwenxu ip_tunnel_init_flow(&fl4, IPPROTO_GRE, key->u.ipv4.dst, key->u.ipv4.src,
633f7716b31SGuillaume Nault tunnel_id_to_key32(key->tun_id),
634db53cd3dSDavid Ahern key->tos & ~INET_ECN_MASK, dev_net(dev), 0,
6357ec9fce4SEyal Birger skb->mark, skb_get_hash(skb), key->flow_flags);
636962924faSwenxu rt = ip_route_output_key(dev_net(dev), &fl4);
637fc4099f1SPravin B Shelar if (IS_ERR(rt))
638fc4099f1SPravin B Shelar return PTR_ERR(rt);
639fc4099f1SPravin B Shelar
640fc4099f1SPravin B Shelar ip_rt_put(rt);
641fc4099f1SPravin B Shelar info->key.u.ipv4.src = fl4.saddr;
642fc4099f1SPravin B Shelar return 0;
643fc4099f1SPravin B Shelar }
644fc4099f1SPravin B Shelar
ipgre_xmit(struct sk_buff * skb,struct net_device * dev)645c5441932SPravin B Shelar static netdev_tx_t ipgre_xmit(struct sk_buff *skb,
646c5441932SPravin B Shelar struct net_device *dev)
647ee34c1ebSMichal Schmidt {
648c5441932SPravin B Shelar struct ip_tunnel *tunnel = netdev_priv(dev);
649c5441932SPravin B Shelar const struct iphdr *tnl_params;
650ee34c1ebSMichal Schmidt
651cb9f1b78SWillem de Bruijn if (!pskb_inet_may_pull(skb))
652cb9f1b78SWillem de Bruijn goto free_skb;
653cb9f1b78SWillem de Bruijn
6542e15ea39SPravin B Shelar if (tunnel->collect_md) {
6552090714eSJiri Benc gre_fb_xmit(skb, dev, skb->protocol);
6562e15ea39SPravin B Shelar return NETDEV_TX_OK;
6572e15ea39SPravin B Shelar }
6582e15ea39SPravin B Shelar
659c5441932SPravin B Shelar if (dev->header_ops) {
66080d875cfSShigeru Yoshida int pull_len = tunnel->hlen + sizeof(struct iphdr);
66180d875cfSShigeru Yoshida
662fdafed45SCong Wang if (skb_cow_head(skb, 0))
663c5441932SPravin B Shelar goto free_skb;
664ee34c1ebSMichal Schmidt
665c5441932SPravin B Shelar tnl_params = (const struct iphdr *)skb->data;
666cbb1e85fSDavid S. Miller
66780d875cfSShigeru Yoshida if (!pskb_network_may_pull(skb, pull_len))
66880d875cfSShigeru Yoshida goto free_skb;
66980d875cfSShigeru Yoshida
67080d875cfSShigeru Yoshida /* ip_tunnel_xmit() needs skb->data pointing to gre header. */
67180d875cfSShigeru Yoshida skb_pull(skb, pull_len);
6728a0033a9STimo Teräs skb_reset_mac_header(skb);
6738d21e996SWillem de Bruijn
6748d21e996SWillem de Bruijn if (skb->ip_summed == CHECKSUM_PARTIAL &&
6758d21e996SWillem de Bruijn skb_checksum_start(skb) < skb->data)
6768d21e996SWillem de Bruijn goto free_skb;
677c5441932SPravin B Shelar } else {
678c5441932SPravin B Shelar if (skb_cow_head(skb, dev->needed_headroom))
679c5441932SPravin B Shelar goto free_skb;
680c5441932SPravin B Shelar
681c5441932SPravin B Shelar tnl_params = &tunnel->parms.iph;
682ee34c1ebSMichal Schmidt }
683e1a80002SHerbert Xu
6845832c4a7SAlexander Lobakin if (gre_handle_offloads(skb, test_bit(IP_TUNNEL_CSUM_BIT,
6855832c4a7SAlexander Lobakin tunnel->parms.o_flags)))
686aed069dfSAlexander Duyck goto free_skb;
6878a0033a9STimo Teräs
688c5441932SPravin B Shelar __gre_xmit(skb, dev, tnl_params, skb->protocol);
689c5441932SPravin B Shelar return NETDEV_TX_OK;
690c5441932SPravin B Shelar
691c5441932SPravin B Shelar free_skb:
6923acfa1e7SEric Dumazet kfree_skb(skb);
693c4794d22SEric Dumazet DEV_STATS_INC(dev, tx_dropped);
694c5441932SPravin B Shelar return NETDEV_TX_OK;
695ee34c1ebSMichal Schmidt }
696ee34c1ebSMichal Schmidt
erspan_xmit(struct sk_buff * skb,struct net_device * dev)69784e54fe0SWilliam Tu static netdev_tx_t erspan_xmit(struct sk_buff *skb,
69884e54fe0SWilliam Tu struct net_device *dev)
69984e54fe0SWilliam Tu {
70084e54fe0SWilliam Tu struct ip_tunnel *tunnel = netdev_priv(dev);
70184e54fe0SWilliam Tu bool truncate = false;
70220704bd1SXin Long __be16 proto;
70384e54fe0SWilliam Tu
704cb9f1b78SWillem de Bruijn if (!pskb_inet_may_pull(skb))
705cb9f1b78SWillem de Bruijn goto free_skb;
706cb9f1b78SWillem de Bruijn
7071a66a836SWilliam Tu if (tunnel->collect_md) {
70820704bd1SXin Long erspan_fb_xmit(skb, dev);
7091a66a836SWilliam Tu return NETDEV_TX_OK;
7101a66a836SWilliam Tu }
7111a66a836SWilliam Tu
71284e54fe0SWilliam Tu if (gre_handle_offloads(skb, false))
71384e54fe0SWilliam Tu goto free_skb;
71484e54fe0SWilliam Tu
71584e54fe0SWilliam Tu if (skb_cow_head(skb, dev->needed_headroom))
71684e54fe0SWilliam Tu goto free_skb;
71784e54fe0SWilliam Tu
718f192970dSWilliam Tu if (skb->len > dev->mtu + dev->hard_header_len) {
719aa7cb378SYuanjun Gong if (pskb_trim(skb, dev->mtu + dev->hard_header_len))
720aa7cb378SYuanjun Gong goto free_skb;
72184e54fe0SWilliam Tu truncate = true;
72284e54fe0SWilliam Tu }
72384e54fe0SWilliam Tu
72484e54fe0SWilliam Tu /* Push ERSPAN header */
725f989d546SWilliam Tu if (tunnel->erspan_ver == 0) {
726f989d546SWilliam Tu proto = htons(ETH_P_ERSPAN);
7275832c4a7SAlexander Lobakin __clear_bit(IP_TUNNEL_SEQ_BIT, tunnel->parms.o_flags);
728f989d546SWilliam Tu } else if (tunnel->erspan_ver == 1) {
729c69de58bSWilliam Tu erspan_build_header(skb, ntohl(tunnel->parms.o_key),
730c69de58bSWilliam Tu tunnel->index,
731a3222dc9SWilliam Tu truncate, true);
73220704bd1SXin Long proto = htons(ETH_P_ERSPAN);
73320704bd1SXin Long } else if (tunnel->erspan_ver == 2) {
734c69de58bSWilliam Tu erspan_build_header_v2(skb, ntohl(tunnel->parms.o_key),
735f551c91dSWilliam Tu tunnel->dir, tunnel->hwid,
736f551c91dSWilliam Tu truncate, true);
73720704bd1SXin Long proto = htons(ETH_P_ERSPAN2);
73820704bd1SXin Long } else {
73902f99df1SWilliam Tu goto free_skb;
74020704bd1SXin Long }
741f551c91dSWilliam Tu
7425832c4a7SAlexander Lobakin __clear_bit(IP_TUNNEL_KEY_BIT, tunnel->parms.o_flags);
74320704bd1SXin Long __gre_xmit(skb, dev, &tunnel->parms.iph, proto);
74484e54fe0SWilliam Tu return NETDEV_TX_OK;
74584e54fe0SWilliam Tu
74684e54fe0SWilliam Tu free_skb:
74784e54fe0SWilliam Tu kfree_skb(skb);
748c4794d22SEric Dumazet DEV_STATS_INC(dev, tx_dropped);
74984e54fe0SWilliam Tu return NETDEV_TX_OK;
75084e54fe0SWilliam Tu }
75184e54fe0SWilliam Tu
gre_tap_xmit(struct sk_buff * skb,struct net_device * dev)752c5441932SPravin B Shelar static netdev_tx_t gre_tap_xmit(struct sk_buff *skb,
753c5441932SPravin B Shelar struct net_device *dev)
754c5441932SPravin B Shelar {
755c5441932SPravin B Shelar struct ip_tunnel *tunnel = netdev_priv(dev);
756ee34c1ebSMichal Schmidt
757cb9f1b78SWillem de Bruijn if (!pskb_inet_may_pull(skb))
758cb9f1b78SWillem de Bruijn goto free_skb;
759cb9f1b78SWillem de Bruijn
7602e15ea39SPravin B Shelar if (tunnel->collect_md) {
7612090714eSJiri Benc gre_fb_xmit(skb, dev, htons(ETH_P_TEB));
7622e15ea39SPravin B Shelar return NETDEV_TX_OK;
7632e15ea39SPravin B Shelar }
7642e15ea39SPravin B Shelar
7655832c4a7SAlexander Lobakin if (gre_handle_offloads(skb, test_bit(IP_TUNNEL_CSUM_BIT,
7665832c4a7SAlexander Lobakin tunnel->parms.o_flags)))
767aed069dfSAlexander Duyck goto free_skb;
768ee34c1ebSMichal Schmidt
769c5441932SPravin B Shelar if (skb_cow_head(skb, dev->needed_headroom))
770c5441932SPravin B Shelar goto free_skb;
77142aa9162SHerbert Xu
772c5441932SPravin B Shelar __gre_xmit(skb, dev, &tunnel->parms.iph, htons(ETH_P_TEB));
773c5441932SPravin B Shelar return NETDEV_TX_OK;
774c5441932SPravin B Shelar
775c5441932SPravin B Shelar free_skb:
7763acfa1e7SEric Dumazet kfree_skb(skb);
777c4794d22SEric Dumazet DEV_STATS_INC(dev, tx_dropped);
778c5441932SPravin B Shelar return NETDEV_TX_OK;
77968c33163SPravin B Shelar }
780ee34c1ebSMichal Schmidt
ipgre_link_update(struct net_device * dev,bool set_mtu)781dd9d598cSXin Long static void ipgre_link_update(struct net_device *dev, bool set_mtu)
782dd9d598cSXin Long {
783dd9d598cSXin Long struct ip_tunnel *tunnel = netdev_priv(dev);
784dd9d598cSXin Long int len;
785dd9d598cSXin Long
786dd9d598cSXin Long len = tunnel->tun_hlen;
787dd9d598cSXin Long tunnel->tun_hlen = gre_calc_hlen(tunnel->parms.o_flags);
788dd9d598cSXin Long len = tunnel->tun_hlen - len;
789dd9d598cSXin Long tunnel->hlen = tunnel->hlen + len;
790dd9d598cSXin Long
791fdafed45SCong Wang if (dev->header_ops)
792fdafed45SCong Wang dev->hard_header_len += len;
793fdafed45SCong Wang else
794fdafed45SCong Wang dev->needed_headroom += len;
795fdafed45SCong Wang
796dd9d598cSXin Long if (set_mtu)
7971eb2cdedSEric Dumazet WRITE_ONCE(dev->mtu, max_t(int, dev->mtu - len, 68));
798dd9d598cSXin Long
7995832c4a7SAlexander Lobakin if (test_bit(IP_TUNNEL_SEQ_BIT, tunnel->parms.o_flags) ||
8005832c4a7SAlexander Lobakin (test_bit(IP_TUNNEL_CSUM_BIT, tunnel->parms.o_flags) &&
8015832c4a7SAlexander Lobakin tunnel->encap.type != TUNNEL_ENCAP_NONE)) {
8021cc5954fSSabrina Dubroca dev->features &= ~NETIF_F_GSO_SOFTWARE;
8031cc5954fSSabrina Dubroca dev->hw_features &= ~NETIF_F_GSO_SOFTWARE;
8041cc5954fSSabrina Dubroca } else {
805020e8f60SPeilin Ye dev->features |= NETIF_F_GSO_SOFTWARE;
806020e8f60SPeilin Ye dev->hw_features |= NETIF_F_GSO_SOFTWARE;
807dd9d598cSXin Long }
808dd9d598cSXin Long }
809dd9d598cSXin Long
ipgre_tunnel_ctl(struct net_device * dev,struct ip_tunnel_parm_kern * p,int cmd)810117aef12SAlexander Lobakin static int ipgre_tunnel_ctl(struct net_device *dev,
811117aef12SAlexander Lobakin struct ip_tunnel_parm_kern *p,
812607259a6SChristoph Hellwig int cmd)
8131da177e4SLinus Torvalds {
8145832c4a7SAlexander Lobakin __be16 i_flags, o_flags;
815a0efab67SXin Long int err;
8161da177e4SLinus Torvalds
8175832c4a7SAlexander Lobakin if (!ip_tunnel_flags_is_be16_compat(p->i_flags) ||
8185832c4a7SAlexander Lobakin !ip_tunnel_flags_is_be16_compat(p->o_flags))
8195832c4a7SAlexander Lobakin return -EOVERFLOW;
8205832c4a7SAlexander Lobakin
8215832c4a7SAlexander Lobakin i_flags = ip_tunnel_flags_to_be16(p->i_flags);
8225832c4a7SAlexander Lobakin o_flags = ip_tunnel_flags_to_be16(p->o_flags);
8235832c4a7SAlexander Lobakin
8246c734fb8SCong Wang if (cmd == SIOCADDTUNNEL || cmd == SIOCCHGTUNNEL) {
825607259a6SChristoph Hellwig if (p->iph.version != 4 || p->iph.protocol != IPPROTO_GRE ||
826607259a6SChristoph Hellwig p->iph.ihl != 5 || (p->iph.frag_off & htons(~IP_DF)) ||
8275832c4a7SAlexander Lobakin ((i_flags | o_flags) & (GRE_VERSION | GRE_ROUTING)))
8281da177e4SLinus Torvalds return -EINVAL;
829c5441932SPravin B Shelar }
830a0efab67SXin Long
8315832c4a7SAlexander Lobakin gre_flags_to_tnl_flags(p->i_flags, i_flags);
8325832c4a7SAlexander Lobakin gre_flags_to_tnl_flags(p->o_flags, o_flags);
833c5441932SPravin B Shelar
834607259a6SChristoph Hellwig err = ip_tunnel_ctl(dev, p, cmd);
835c5441932SPravin B Shelar if (err)
836c5441932SPravin B Shelar return err;
837c5441932SPravin B Shelar
838a0efab67SXin Long if (cmd == SIOCCHGTUNNEL) {
839a0efab67SXin Long struct ip_tunnel *t = netdev_priv(dev);
840a0efab67SXin Long
8415832c4a7SAlexander Lobakin ip_tunnel_flags_copy(t->parms.i_flags, p->i_flags);
8425832c4a7SAlexander Lobakin ip_tunnel_flags_copy(t->parms.o_flags, p->o_flags);
843a0efab67SXin Long
844a0efab67SXin Long if (strcmp(dev->rtnl_link_ops->kind, "erspan"))
845a0efab67SXin Long ipgre_link_update(dev, true);
846a0efab67SXin Long }
847a0efab67SXin Long
8485832c4a7SAlexander Lobakin i_flags = gre_tnl_flags_to_gre_flags(p->i_flags);
8495832c4a7SAlexander Lobakin ip_tunnel_flags_from_be16(p->i_flags, i_flags);
8505832c4a7SAlexander Lobakin o_flags = gre_tnl_flags_to_gre_flags(p->o_flags);
8515832c4a7SAlexander Lobakin ip_tunnel_flags_from_be16(p->o_flags, o_flags);
8525832c4a7SAlexander Lobakin
8531da177e4SLinus Torvalds return 0;
8541da177e4SLinus Torvalds }
8551da177e4SLinus Torvalds
8561da177e4SLinus Torvalds /* Nice toy. Unfortunately, useless in real life :-)
8571da177e4SLinus Torvalds It allows to construct virtual multiprotocol broadcast "LAN"
8581da177e4SLinus Torvalds over the Internet, provided multicast routing is tuned.
8591da177e4SLinus Torvalds
8601da177e4SLinus Torvalds
8611da177e4SLinus Torvalds I have no idea was this bicycle invented before me,
8621da177e4SLinus Torvalds so that I had to set ARPHRD_IPGRE to a random value.
8631da177e4SLinus Torvalds I have an impression, that Cisco could make something similar,
8641da177e4SLinus Torvalds but this feature is apparently missing in IOS<=11.2(8).
8651da177e4SLinus Torvalds
8661da177e4SLinus Torvalds I set up 10.66.66/24 and fec0:6666:6666::0/96 as virtual networks
8671da177e4SLinus Torvalds with broadcast 224.66.66.66. If you have access to mbone, play with me :-)
8681da177e4SLinus Torvalds
8691da177e4SLinus Torvalds ping -t 255 224.66.66.66
8701da177e4SLinus Torvalds
8711da177e4SLinus Torvalds If nobody answers, mbone does not work.
8721da177e4SLinus Torvalds
8731da177e4SLinus Torvalds ip tunnel add Universe mode gre remote 224.66.66.66 local <Your_real_addr> ttl 255
8741da177e4SLinus Torvalds ip addr add 10.66.66.<somewhat>/24 dev Universe
8751da177e4SLinus Torvalds ifconfig Universe up
8761da177e4SLinus Torvalds ifconfig Universe add fe80::<Your_real_addr>/10
8771da177e4SLinus Torvalds ifconfig Universe add fec0:6666:6666::<Your_real_addr>/96
8781da177e4SLinus Torvalds ftp 10.66.66.66
8791da177e4SLinus Torvalds ...
8801da177e4SLinus Torvalds ftp fec0:6666:6666::193.233.7.65
8811da177e4SLinus Torvalds ...
8821da177e4SLinus Torvalds */
ipgre_header(struct sk_buff * skb,struct net_device * dev,unsigned short type,const void * daddr,const void * saddr,unsigned int len)8833b04dddeSStephen Hemminger static int ipgre_header(struct sk_buff *skb, struct net_device *dev,
8843b04dddeSStephen Hemminger unsigned short type,
8851507850bSEric Dumazet const void *daddr, const void *saddr, unsigned int len)
8861da177e4SLinus Torvalds {
8872941a486SPatrick McHardy struct ip_tunnel *t = netdev_priv(dev);
888c5441932SPravin B Shelar struct iphdr *iph;
889c5441932SPravin B Shelar struct gre_base_hdr *greh;
890c5441932SPravin B Shelar
891d58ff351SJohannes Berg iph = skb_push(skb, t->hlen + sizeof(*iph));
892c5441932SPravin B Shelar greh = (struct gre_base_hdr *)(iph+1);
89395f5c64cSTom Herbert greh->flags = gre_tnl_flags_to_gre_flags(t->parms.o_flags);
894c5441932SPravin B Shelar greh->protocol = htons(type);
8951da177e4SLinus Torvalds
8961da177e4SLinus Torvalds memcpy(iph, &t->parms.iph, sizeof(struct iphdr));
8971da177e4SLinus Torvalds
898c5441932SPravin B Shelar /* Set the source hardware address. */
8991da177e4SLinus Torvalds if (saddr)
9001da177e4SLinus Torvalds memcpy(&iph->saddr, saddr, 4);
9016d55cb91STimo Teräs if (daddr)
9021da177e4SLinus Torvalds memcpy(&iph->daddr, daddr, 4);
9036d55cb91STimo Teräs if (iph->daddr)
90477a482bdSTimo Teräs return t->hlen + sizeof(*iph);
9051da177e4SLinus Torvalds
906c5441932SPravin B Shelar return -(t->hlen + sizeof(*iph));
9071da177e4SLinus Torvalds }
9081da177e4SLinus Torvalds
ipgre_header_parse(const struct sk_buff * skb,unsigned char * haddr)9096a5f44d7STimo Teras static int ipgre_header_parse(const struct sk_buff *skb, unsigned char *haddr)
9106a5f44d7STimo Teras {
911b71d1d42SEric Dumazet const struct iphdr *iph = (const struct iphdr *) skb_mac_header(skb);
9126a5f44d7STimo Teras memcpy(haddr, &iph->saddr, 4);
9136a5f44d7STimo Teras return 4;
9146a5f44d7STimo Teras }
9156a5f44d7STimo Teras
9163b04dddeSStephen Hemminger static const struct header_ops ipgre_header_ops = {
9173b04dddeSStephen Hemminger .create = ipgre_header,
9186a5f44d7STimo Teras .parse = ipgre_header_parse,
9193b04dddeSStephen Hemminger };
9203b04dddeSStephen Hemminger
9216a5f44d7STimo Teras #ifdef CONFIG_NET_IPGRE_BROADCAST
ipgre_open(struct net_device * dev)9221da177e4SLinus Torvalds static int ipgre_open(struct net_device *dev)
9231da177e4SLinus Torvalds {
9242941a486SPatrick McHardy struct ip_tunnel *t = netdev_priv(dev);
9251da177e4SLinus Torvalds
926f97c1e0cSJoe Perches if (ipv4_is_multicast(t->parms.iph.daddr)) {
927cbb1e85fSDavid S. Miller struct flowi4 fl4;
928cbb1e85fSDavid S. Miller struct rtable *rt;
929cbb1e85fSDavid S. Miller
930b57708adSNicolas Dichtel rt = ip_route_output_gre(t->net, &fl4,
93178fbfd8aSDavid S. Miller t->parms.iph.daddr,
93278fbfd8aSDavid S. Miller t->parms.iph.saddr,
93378fbfd8aSDavid S. Miller t->parms.o_key,
934*25376a89SIdo Schimmel t->parms.iph.tos & INET_DSCP_MASK,
93578fbfd8aSDavid S. Miller t->parms.link);
936b23dd4feSDavid S. Miller if (IS_ERR(rt))
9371da177e4SLinus Torvalds return -EADDRNOTAVAIL;
938d8d1f30bSChangli Gao dev = rt->dst.dev;
9391da177e4SLinus Torvalds ip_rt_put(rt);
94051456b29SIan Morris if (!__in_dev_get_rtnl(dev))
9411da177e4SLinus Torvalds return -EADDRNOTAVAIL;
9421da177e4SLinus Torvalds t->mlink = dev->ifindex;
943e5ed6399SHerbert Xu ip_mc_inc_group(__in_dev_get_rtnl(dev), t->parms.iph.daddr);
9441da177e4SLinus Torvalds }
9451da177e4SLinus Torvalds return 0;
9461da177e4SLinus Torvalds }
9471da177e4SLinus Torvalds
ipgre_close(struct net_device * dev)9481da177e4SLinus Torvalds static int ipgre_close(struct net_device *dev)
9491da177e4SLinus Torvalds {
9502941a486SPatrick McHardy struct ip_tunnel *t = netdev_priv(dev);
951b8c26a33SStephen Hemminger
952f97c1e0cSJoe Perches if (ipv4_is_multicast(t->parms.iph.daddr) && t->mlink) {
9537fee0ca2SDenis V. Lunev struct in_device *in_dev;
954b57708adSNicolas Dichtel in_dev = inetdev_by_index(t->net, t->mlink);
9558723e1b4SEric Dumazet if (in_dev)
9561da177e4SLinus Torvalds ip_mc_dec_group(in_dev, t->parms.iph.daddr);
9571da177e4SLinus Torvalds }
9581da177e4SLinus Torvalds return 0;
9591da177e4SLinus Torvalds }
9601da177e4SLinus Torvalds #endif
9611da177e4SLinus Torvalds
962b8c26a33SStephen Hemminger static const struct net_device_ops ipgre_netdev_ops = {
963b8c26a33SStephen Hemminger .ndo_init = ipgre_tunnel_init,
964c5441932SPravin B Shelar .ndo_uninit = ip_tunnel_uninit,
965b8c26a33SStephen Hemminger #ifdef CONFIG_NET_IPGRE_BROADCAST
966b8c26a33SStephen Hemminger .ndo_open = ipgre_open,
967b8c26a33SStephen Hemminger .ndo_stop = ipgre_close,
968b8c26a33SStephen Hemminger #endif
969c5441932SPravin B Shelar .ndo_start_xmit = ipgre_xmit,
9703e7a1c7cSArnd Bergmann .ndo_siocdevprivate = ip_tunnel_siocdevprivate,
971c5441932SPravin B Shelar .ndo_change_mtu = ip_tunnel_change_mtu,
97298d7fc46SHeiner Kallweit .ndo_get_stats64 = dev_get_tstats64,
9731e99584bSNicolas Dichtel .ndo_get_iflink = ip_tunnel_get_iflink,
974607259a6SChristoph Hellwig .ndo_tunnel_ctl = ipgre_tunnel_ctl,
975b8c26a33SStephen Hemminger };
976b8c26a33SStephen Hemminger
9776b78f16eSEric Dumazet #define GRE_FEATURES (NETIF_F_SG | \
9786b78f16eSEric Dumazet NETIF_F_FRAGLIST | \
9796b78f16eSEric Dumazet NETIF_F_HIGHDMA | \
9806b78f16eSEric Dumazet NETIF_F_HW_CSUM)
9816b78f16eSEric Dumazet
ipgre_tunnel_setup(struct net_device * dev)9821da177e4SLinus Torvalds static void ipgre_tunnel_setup(struct net_device *dev)
9831da177e4SLinus Torvalds {
984b8c26a33SStephen Hemminger dev->netdev_ops = &ipgre_netdev_ops;
9855a455275SNicolas Dichtel dev->type = ARPHRD_IPGRE;
986c5441932SPravin B Shelar ip_tunnel_setup(dev, ipgre_net_id);
987c5441932SPravin B Shelar }
9881da177e4SLinus Torvalds
__gre_tunnel_init(struct net_device * dev)989c5441932SPravin B Shelar static void __gre_tunnel_init(struct net_device *dev)
990c5441932SPravin B Shelar {
991c5441932SPravin B Shelar struct ip_tunnel *tunnel;
992c5441932SPravin B Shelar
993c5441932SPravin B Shelar tunnel = netdev_priv(dev);
99495f5c64cSTom Herbert tunnel->tun_hlen = gre_calc_hlen(tunnel->parms.o_flags);
995c5441932SPravin B Shelar tunnel->parms.iph.protocol = IPPROTO_GRE;
996c5441932SPravin B Shelar
9974565e991STom Herbert tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen;
998fdafed45SCong Wang dev->needed_headroom = tunnel->hlen + sizeof(tunnel->parms.iph);
9994565e991STom Herbert
100000d066a4SAlexander Lobakin dev->features |= GRE_FEATURES;
10016b78f16eSEric Dumazet dev->hw_features |= GRE_FEATURES;
1002c5441932SPravin B Shelar
1003020e8f60SPeilin Ye /* TCP offload with GRE SEQ is not supported, nor can we support 2
1004020e8f60SPeilin Ye * levels of outer headers requiring an update.
1005a0ca153fSAlexander Duyck */
10065832c4a7SAlexander Lobakin if (test_bit(IP_TUNNEL_SEQ_BIT, tunnel->parms.o_flags))
1007020e8f60SPeilin Ye return;
10085832c4a7SAlexander Lobakin if (test_bit(IP_TUNNEL_CSUM_BIT, tunnel->parms.o_flags) &&
10095832c4a7SAlexander Lobakin tunnel->encap.type != TUNNEL_ENCAP_NONE)
1010020e8f60SPeilin Ye return;
1011020e8f60SPeilin Ye
1012c5441932SPravin B Shelar dev->features |= NETIF_F_GSO_SOFTWARE;
1013c5441932SPravin B Shelar dev->hw_features |= NETIF_F_GSO_SOFTWARE;
101400d066a4SAlexander Lobakin
101500d066a4SAlexander Lobakin dev->lltx = true;
1016a0ca153fSAlexander Duyck }
1017a0ca153fSAlexander Duyck
ipgre_tunnel_init(struct net_device * dev)10181da177e4SLinus Torvalds static int ipgre_tunnel_init(struct net_device *dev)
10191da177e4SLinus Torvalds {
1020c5441932SPravin B Shelar struct ip_tunnel *tunnel = netdev_priv(dev);
1021c5441932SPravin B Shelar struct iphdr *iph = &tunnel->parms.iph;
10221da177e4SLinus Torvalds
1023c5441932SPravin B Shelar __gre_tunnel_init(dev);
10241da177e4SLinus Torvalds
10255a1b7e1aSJakub Kicinski __dev_addr_set(dev, &iph->saddr, 4);
1026c5441932SPravin B Shelar memcpy(dev->broadcast, &iph->daddr, 4);
10271da177e4SLinus Torvalds
1028c5441932SPravin B Shelar dev->flags = IFF_NOARP;
102902875878SEric Dumazet netif_keep_dst(dev);
1030c5441932SPravin B Shelar dev->addr_len = 4;
10311da177e4SLinus Torvalds
1032a64b04d8SJiri Benc if (iph->daddr && !tunnel->collect_md) {
10331da177e4SLinus Torvalds #ifdef CONFIG_NET_IPGRE_BROADCAST
1034f97c1e0cSJoe Perches if (ipv4_is_multicast(iph->daddr)) {
10351da177e4SLinus Torvalds if (!iph->saddr)
10361da177e4SLinus Torvalds return -EINVAL;
10371da177e4SLinus Torvalds dev->flags = IFF_BROADCAST;
10383b04dddeSStephen Hemminger dev->header_ops = &ipgre_header_ops;
1039fdafed45SCong Wang dev->hard_header_len = tunnel->hlen + sizeof(*iph);
1040fdafed45SCong Wang dev->needed_headroom = 0;
10411da177e4SLinus Torvalds }
10421da177e4SLinus Torvalds #endif
1043a64b04d8SJiri Benc } else if (!tunnel->collect_md) {
10446a5f44d7STimo Teras dev->header_ops = &ipgre_header_ops;
1045fdafed45SCong Wang dev->hard_header_len = tunnel->hlen + sizeof(*iph);
1046fdafed45SCong Wang dev->needed_headroom = 0;
1047a64b04d8SJiri Benc }
10481da177e4SLinus Torvalds
1049c5441932SPravin B Shelar return ip_tunnel_init(dev);
105060769a5dSEric Dumazet }
105160769a5dSEric Dumazet
10529f57c67cSPravin B Shelar static const struct gre_protocol ipgre_protocol = {
10539f57c67cSPravin B Shelar .handler = gre_rcv,
10549f57c67cSPravin B Shelar .err_handler = gre_err,
10551da177e4SLinus Torvalds };
10561da177e4SLinus Torvalds
ipgre_init_net(struct net * net)10572c8c1e72SAlexey Dobriyan static int __net_init ipgre_init_net(struct net *net)
105859a4c759SPavel Emelyanov {
1059c5441932SPravin B Shelar return ip_tunnel_init_net(net, ipgre_net_id, &ipgre_link_ops, NULL);
106059a4c759SPavel Emelyanov }
106159a4c759SPavel Emelyanov
ipgre_exit_batch_rtnl(struct list_head * list_net,struct list_head * dev_to_kill)10629b5b3637SEric Dumazet static void __net_exit ipgre_exit_batch_rtnl(struct list_head *list_net,
10639b5b3637SEric Dumazet struct list_head *dev_to_kill)
106459a4c759SPavel Emelyanov {
10659b5b3637SEric Dumazet ip_tunnel_delete_nets(list_net, ipgre_net_id, &ipgre_link_ops,
10669b5b3637SEric Dumazet dev_to_kill);
106759a4c759SPavel Emelyanov }
106859a4c759SPavel Emelyanov
106959a4c759SPavel Emelyanov static struct pernet_operations ipgre_net_ops = {
107059a4c759SPavel Emelyanov .init = ipgre_init_net,
10719b5b3637SEric Dumazet .exit_batch_rtnl = ipgre_exit_batch_rtnl,
1072cfb8fbf2SEric W. Biederman .id = &ipgre_net_id,
1073c5441932SPravin B Shelar .size = sizeof(struct ip_tunnel_net),
107459a4c759SPavel Emelyanov };
10751da177e4SLinus Torvalds
ipgre_tunnel_validate(struct nlattr * tb[],struct nlattr * data[],struct netlink_ext_ack * extack)1076a8b8a889SMatthias Schiffer static int ipgre_tunnel_validate(struct nlattr *tb[], struct nlattr *data[],
1077a8b8a889SMatthias Schiffer struct netlink_ext_ack *extack)
1078c19e654dSHerbert Xu {
1079c19e654dSHerbert Xu __be16 flags;
1080c19e654dSHerbert Xu
1081c19e654dSHerbert Xu if (!data)
1082c19e654dSHerbert Xu return 0;
1083c19e654dSHerbert Xu
1084c19e654dSHerbert Xu flags = 0;
1085c19e654dSHerbert Xu if (data[IFLA_GRE_IFLAGS])
1086c19e654dSHerbert Xu flags |= nla_get_be16(data[IFLA_GRE_IFLAGS]);
1087c19e654dSHerbert Xu if (data[IFLA_GRE_OFLAGS])
1088c19e654dSHerbert Xu flags |= nla_get_be16(data[IFLA_GRE_OFLAGS]);
1089c19e654dSHerbert Xu if (flags & (GRE_VERSION|GRE_ROUTING))
1090c19e654dSHerbert Xu return -EINVAL;
1091c19e654dSHerbert Xu
1092946b636fSJiri Benc if (data[IFLA_GRE_COLLECT_METADATA] &&
1093946b636fSJiri Benc data[IFLA_GRE_ENCAP_TYPE] &&
1094946b636fSJiri Benc nla_get_u16(data[IFLA_GRE_ENCAP_TYPE]) != TUNNEL_ENCAP_NONE)
1095946b636fSJiri Benc return -EINVAL;
1096946b636fSJiri Benc
1097c19e654dSHerbert Xu return 0;
1098c19e654dSHerbert Xu }
1099c19e654dSHerbert Xu
ipgre_tap_validate(struct nlattr * tb[],struct nlattr * data[],struct netlink_ext_ack * extack)1100a8b8a889SMatthias Schiffer static int ipgre_tap_validate(struct nlattr *tb[], struct nlattr *data[],
1101a8b8a889SMatthias Schiffer struct netlink_ext_ack *extack)
1102e1a80002SHerbert Xu {
1103e1a80002SHerbert Xu __be32 daddr;
1104e1a80002SHerbert Xu
1105e1a80002SHerbert Xu if (tb[IFLA_ADDRESS]) {
1106e1a80002SHerbert Xu if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN)
1107e1a80002SHerbert Xu return -EINVAL;
1108e1a80002SHerbert Xu if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS])))
1109e1a80002SHerbert Xu return -EADDRNOTAVAIL;
1110e1a80002SHerbert Xu }
1111e1a80002SHerbert Xu
1112e1a80002SHerbert Xu if (!data)
1113e1a80002SHerbert Xu goto out;
1114e1a80002SHerbert Xu
1115e1a80002SHerbert Xu if (data[IFLA_GRE_REMOTE]) {
1116e1a80002SHerbert Xu memcpy(&daddr, nla_data(data[IFLA_GRE_REMOTE]), 4);
1117e1a80002SHerbert Xu if (!daddr)
1118e1a80002SHerbert Xu return -EINVAL;
1119e1a80002SHerbert Xu }
1120e1a80002SHerbert Xu
1121e1a80002SHerbert Xu out:
1122a8b8a889SMatthias Schiffer return ipgre_tunnel_validate(tb, data, extack);
1123e1a80002SHerbert Xu }
1124e1a80002SHerbert Xu
erspan_validate(struct nlattr * tb[],struct nlattr * data[],struct netlink_ext_ack * extack)112584e54fe0SWilliam Tu static int erspan_validate(struct nlattr *tb[], struct nlattr *data[],
112684e54fe0SWilliam Tu struct netlink_ext_ack *extack)
112784e54fe0SWilliam Tu {
112884e54fe0SWilliam Tu __be16 flags = 0;
112984e54fe0SWilliam Tu int ret;
113084e54fe0SWilliam Tu
113184e54fe0SWilliam Tu if (!data)
113284e54fe0SWilliam Tu return 0;
113384e54fe0SWilliam Tu
113484e54fe0SWilliam Tu ret = ipgre_tap_validate(tb, data, extack);
113584e54fe0SWilliam Tu if (ret)
113684e54fe0SWilliam Tu return ret;
113784e54fe0SWilliam Tu
113851fa960dSWilliam Tu if (data[IFLA_GRE_ERSPAN_VER] &&
113951fa960dSWilliam Tu nla_get_u8(data[IFLA_GRE_ERSPAN_VER]) == 0)
1140f989d546SWilliam Tu return 0;
1141f989d546SWilliam Tu
1142f989d546SWilliam Tu /* ERSPAN type II/III should only have GRE sequence and key flag */
11431a66a836SWilliam Tu if (data[IFLA_GRE_OFLAGS])
114484e54fe0SWilliam Tu flags |= nla_get_be16(data[IFLA_GRE_OFLAGS]);
11451a66a836SWilliam Tu if (data[IFLA_GRE_IFLAGS])
114684e54fe0SWilliam Tu flags |= nla_get_be16(data[IFLA_GRE_IFLAGS]);
11471a66a836SWilliam Tu if (!data[IFLA_GRE_COLLECT_METADATA] &&
11481a66a836SWilliam Tu flags != (GRE_SEQ | GRE_KEY))
114984e54fe0SWilliam Tu return -EINVAL;
115084e54fe0SWilliam Tu
115184e54fe0SWilliam Tu /* ERSPAN Session ID only has 10-bit. Since we reuse
115284e54fe0SWilliam Tu * 32-bit key field as ID, check it's range.
115384e54fe0SWilliam Tu */
115484e54fe0SWilliam Tu if (data[IFLA_GRE_IKEY] &&
115584e54fe0SWilliam Tu (ntohl(nla_get_be32(data[IFLA_GRE_IKEY])) & ~ID_MASK))
115684e54fe0SWilliam Tu return -EINVAL;
115784e54fe0SWilliam Tu
115884e54fe0SWilliam Tu if (data[IFLA_GRE_OKEY] &&
115984e54fe0SWilliam Tu (ntohl(nla_get_be32(data[IFLA_GRE_OKEY])) & ~ID_MASK))
116084e54fe0SWilliam Tu return -EINVAL;
116184e54fe0SWilliam Tu
116284e54fe0SWilliam Tu return 0;
116384e54fe0SWilliam Tu }
116484e54fe0SWilliam Tu
ipgre_netlink_parms(struct net_device * dev,struct nlattr * data[],struct nlattr * tb[],struct ip_tunnel_parm_kern * parms,__u32 * fwmark)116522a59be8SPhilip Prindeville static int ipgre_netlink_parms(struct net_device *dev,
11662e15ea39SPravin B Shelar struct nlattr *data[],
11672e15ea39SPravin B Shelar struct nlattr *tb[],
1168117aef12SAlexander Lobakin struct ip_tunnel_parm_kern *parms,
11699830ad4cSCraig Gallek __u32 *fwmark)
1170c19e654dSHerbert Xu {
117122a59be8SPhilip Prindeville struct ip_tunnel *t = netdev_priv(dev);
117222a59be8SPhilip Prindeville
11737bb82d92SHerbert Xu memset(parms, 0, sizeof(*parms));
1174c19e654dSHerbert Xu
1175c19e654dSHerbert Xu parms->iph.protocol = IPPROTO_GRE;
1176c19e654dSHerbert Xu
1177c19e654dSHerbert Xu if (!data)
117822a59be8SPhilip Prindeville return 0;
1179c19e654dSHerbert Xu
1180c19e654dSHerbert Xu if (data[IFLA_GRE_LINK])
1181c19e654dSHerbert Xu parms->link = nla_get_u32(data[IFLA_GRE_LINK]);
1182c19e654dSHerbert Xu
1183c19e654dSHerbert Xu if (data[IFLA_GRE_IFLAGS])
11845832c4a7SAlexander Lobakin gre_flags_to_tnl_flags(parms->i_flags,
11855832c4a7SAlexander Lobakin nla_get_be16(data[IFLA_GRE_IFLAGS]));
1186c19e654dSHerbert Xu
1187c19e654dSHerbert Xu if (data[IFLA_GRE_OFLAGS])
11885832c4a7SAlexander Lobakin gre_flags_to_tnl_flags(parms->o_flags,
11895832c4a7SAlexander Lobakin nla_get_be16(data[IFLA_GRE_OFLAGS]));
1190c19e654dSHerbert Xu
1191c19e654dSHerbert Xu if (data[IFLA_GRE_IKEY])
1192c19e654dSHerbert Xu parms->i_key = nla_get_be32(data[IFLA_GRE_IKEY]);
1193c19e654dSHerbert Xu
1194c19e654dSHerbert Xu if (data[IFLA_GRE_OKEY])
1195c19e654dSHerbert Xu parms->o_key = nla_get_be32(data[IFLA_GRE_OKEY]);
1196c19e654dSHerbert Xu
1197c19e654dSHerbert Xu if (data[IFLA_GRE_LOCAL])
119867b61f6cSJiri Benc parms->iph.saddr = nla_get_in_addr(data[IFLA_GRE_LOCAL]);
1199c19e654dSHerbert Xu
1200c19e654dSHerbert Xu if (data[IFLA_GRE_REMOTE])
120167b61f6cSJiri Benc parms->iph.daddr = nla_get_in_addr(data[IFLA_GRE_REMOTE]);
1202c19e654dSHerbert Xu
1203c19e654dSHerbert Xu if (data[IFLA_GRE_TTL])
1204c19e654dSHerbert Xu parms->iph.ttl = nla_get_u8(data[IFLA_GRE_TTL]);
1205c19e654dSHerbert Xu
1206c19e654dSHerbert Xu if (data[IFLA_GRE_TOS])
1207c19e654dSHerbert Xu parms->iph.tos = nla_get_u8(data[IFLA_GRE_TOS]);
1208c19e654dSHerbert Xu
120922a59be8SPhilip Prindeville if (!data[IFLA_GRE_PMTUDISC] || nla_get_u8(data[IFLA_GRE_PMTUDISC])) {
121022a59be8SPhilip Prindeville if (t->ignore_df)
121122a59be8SPhilip Prindeville return -EINVAL;
1212c19e654dSHerbert Xu parms->iph.frag_off = htons(IP_DF);
121322a59be8SPhilip Prindeville }
12142e15ea39SPravin B Shelar
12152e15ea39SPravin B Shelar if (data[IFLA_GRE_COLLECT_METADATA]) {
12162e15ea39SPravin B Shelar t->collect_md = true;
1217e271c7b4SJiri Benc if (dev->type == ARPHRD_IPGRE)
1218e271c7b4SJiri Benc dev->type = ARPHRD_NONE;
12192e15ea39SPravin B Shelar }
122022a59be8SPhilip Prindeville
122122a59be8SPhilip Prindeville if (data[IFLA_GRE_IGNORE_DF]) {
122222a59be8SPhilip Prindeville if (nla_get_u8(data[IFLA_GRE_IGNORE_DF])
122322a59be8SPhilip Prindeville && (parms->iph.frag_off & htons(IP_DF)))
122422a59be8SPhilip Prindeville return -EINVAL;
122522a59be8SPhilip Prindeville t->ignore_df = !!nla_get_u8(data[IFLA_GRE_IGNORE_DF]);
122622a59be8SPhilip Prindeville }
122722a59be8SPhilip Prindeville
12289830ad4cSCraig Gallek if (data[IFLA_GRE_FWMARK])
12299830ad4cSCraig Gallek *fwmark = nla_get_u32(data[IFLA_GRE_FWMARK]);
12309830ad4cSCraig Gallek
1231e1f8f78fSPetr Machata return 0;
1232e1f8f78fSPetr Machata }
1233e1f8f78fSPetr Machata
erspan_netlink_parms(struct net_device * dev,struct nlattr * data[],struct nlattr * tb[],struct ip_tunnel_parm_kern * parms,__u32 * fwmark)1234e1f8f78fSPetr Machata static int erspan_netlink_parms(struct net_device *dev,
1235e1f8f78fSPetr Machata struct nlattr *data[],
1236e1f8f78fSPetr Machata struct nlattr *tb[],
1237117aef12SAlexander Lobakin struct ip_tunnel_parm_kern *parms,
1238e1f8f78fSPetr Machata __u32 *fwmark)
1239e1f8f78fSPetr Machata {
1240e1f8f78fSPetr Machata struct ip_tunnel *t = netdev_priv(dev);
1241e1f8f78fSPetr Machata int err;
1242e1f8f78fSPetr Machata
1243e1f8f78fSPetr Machata err = ipgre_netlink_parms(dev, data, tb, parms, fwmark);
1244e1f8f78fSPetr Machata if (err)
1245e1f8f78fSPetr Machata return err;
124632ca98feSPetr Machata if (!data)
124732ca98feSPetr Machata return 0;
1248e1f8f78fSPetr Machata
1249f551c91dSWilliam Tu if (data[IFLA_GRE_ERSPAN_VER]) {
1250f551c91dSWilliam Tu t->erspan_ver = nla_get_u8(data[IFLA_GRE_ERSPAN_VER]);
1251f551c91dSWilliam Tu
1252f989d546SWilliam Tu if (t->erspan_ver > 2)
1253f551c91dSWilliam Tu return -EINVAL;
1254f551c91dSWilliam Tu }
1255f551c91dSWilliam Tu
1256f551c91dSWilliam Tu if (t->erspan_ver == 1) {
125784e54fe0SWilliam Tu if (data[IFLA_GRE_ERSPAN_INDEX]) {
125884e54fe0SWilliam Tu t->index = nla_get_u32(data[IFLA_GRE_ERSPAN_INDEX]);
125984e54fe0SWilliam Tu if (t->index & ~INDEX_MASK)
126084e54fe0SWilliam Tu return -EINVAL;
126184e54fe0SWilliam Tu }
1262f551c91dSWilliam Tu } else if (t->erspan_ver == 2) {
1263f551c91dSWilliam Tu if (data[IFLA_GRE_ERSPAN_DIR]) {
1264f551c91dSWilliam Tu t->dir = nla_get_u8(data[IFLA_GRE_ERSPAN_DIR]);
1265f551c91dSWilliam Tu if (t->dir & ~(DIR_MASK >> DIR_OFFSET))
1266f551c91dSWilliam Tu return -EINVAL;
1267f551c91dSWilliam Tu }
1268f551c91dSWilliam Tu if (data[IFLA_GRE_ERSPAN_HWID]) {
1269f551c91dSWilliam Tu t->hwid = nla_get_u16(data[IFLA_GRE_ERSPAN_HWID]);
1270f551c91dSWilliam Tu if (t->hwid & ~(HWID_MASK >> HWID_OFFSET))
1271f551c91dSWilliam Tu return -EINVAL;
1272f551c91dSWilliam Tu }
1273f551c91dSWilliam Tu }
127484e54fe0SWilliam Tu
127522a59be8SPhilip Prindeville return 0;
1276c19e654dSHerbert Xu }
1277c19e654dSHerbert Xu
12784565e991STom 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)12794565e991STom Herbert static bool ipgre_netlink_encap_parms(struct nlattr *data[],
12804565e991STom Herbert struct ip_tunnel_encap *ipencap)
12814565e991STom Herbert {
12824565e991STom Herbert bool ret = false;
12834565e991STom Herbert
12844565e991STom Herbert memset(ipencap, 0, sizeof(*ipencap));
12854565e991STom Herbert
12864565e991STom Herbert if (!data)
12874565e991STom Herbert return ret;
12884565e991STom Herbert
12894565e991STom Herbert if (data[IFLA_GRE_ENCAP_TYPE]) {
12904565e991STom Herbert ret = true;
12914565e991STom Herbert ipencap->type = nla_get_u16(data[IFLA_GRE_ENCAP_TYPE]);
12924565e991STom Herbert }
12934565e991STom Herbert
12944565e991STom Herbert if (data[IFLA_GRE_ENCAP_FLAGS]) {
12954565e991STom Herbert ret = true;
12964565e991STom Herbert ipencap->flags = nla_get_u16(data[IFLA_GRE_ENCAP_FLAGS]);
12974565e991STom Herbert }
12984565e991STom Herbert
12994565e991STom Herbert if (data[IFLA_GRE_ENCAP_SPORT]) {
13004565e991STom Herbert ret = true;
13013e97fa70SSabrina Dubroca ipencap->sport = nla_get_be16(data[IFLA_GRE_ENCAP_SPORT]);
13024565e991STom Herbert }
13034565e991STom Herbert
13044565e991STom Herbert if (data[IFLA_GRE_ENCAP_DPORT]) {
13054565e991STom Herbert ret = true;
13063e97fa70SSabrina Dubroca ipencap->dport = nla_get_be16(data[IFLA_GRE_ENCAP_DPORT]);
13074565e991STom Herbert }
13084565e991STom Herbert
13094565e991STom Herbert return ret;
13104565e991STom Herbert }
13114565e991STom Herbert
gre_tap_init(struct net_device * dev)1312c5441932SPravin B Shelar static int gre_tap_init(struct net_device *dev)
1313e1a80002SHerbert Xu {
1314c5441932SPravin B Shelar __gre_tunnel_init(dev);
1315bec94d43Sstephen hemminger dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
1316d51711c0SXin Long netif_keep_dst(dev);
1317e1a80002SHerbert Xu
1318c5441932SPravin B Shelar return ip_tunnel_init(dev);
1319e1a80002SHerbert Xu }
1320e1a80002SHerbert Xu
1321c5441932SPravin B Shelar static const struct net_device_ops gre_tap_netdev_ops = {
1322c5441932SPravin B Shelar .ndo_init = gre_tap_init,
1323c5441932SPravin B Shelar .ndo_uninit = ip_tunnel_uninit,
1324c5441932SPravin B Shelar .ndo_start_xmit = gre_tap_xmit,
1325b8c26a33SStephen Hemminger .ndo_set_mac_address = eth_mac_addr,
1326b8c26a33SStephen Hemminger .ndo_validate_addr = eth_validate_addr,
1327c5441932SPravin B Shelar .ndo_change_mtu = ip_tunnel_change_mtu,
132898d7fc46SHeiner Kallweit .ndo_get_stats64 = dev_get_tstats64,
13291e99584bSNicolas Dichtel .ndo_get_iflink = ip_tunnel_get_iflink,
1330fc4099f1SPravin B Shelar .ndo_fill_metadata_dst = gre_fill_metadata_dst,
1331b8c26a33SStephen Hemminger };
1332b8c26a33SStephen Hemminger
erspan_tunnel_init(struct net_device * dev)133384e54fe0SWilliam Tu static int erspan_tunnel_init(struct net_device *dev)
133484e54fe0SWilliam Tu {
133584e54fe0SWilliam Tu struct ip_tunnel *tunnel = netdev_priv(dev);
133684e54fe0SWilliam Tu
1337f989d546SWilliam Tu if (tunnel->erspan_ver == 0)
1338f989d546SWilliam Tu tunnel->tun_hlen = 4; /* 4-byte GRE hdr. */
1339f989d546SWilliam Tu else
1340f989d546SWilliam Tu tunnel->tun_hlen = 8; /* 8-byte GRE hdr. */
1341f989d546SWilliam Tu
134284e54fe0SWilliam Tu tunnel->parms.iph.protocol = IPPROTO_GRE;
1343c122fda2SXin Long tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen +
1344f551c91dSWilliam Tu erspan_hdr_len(tunnel->erspan_ver);
134584e54fe0SWilliam Tu
134684e54fe0SWilliam Tu dev->features |= GRE_FEATURES;
134784e54fe0SWilliam Tu dev->hw_features |= GRE_FEATURES;
134884e54fe0SWilliam Tu dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
1349c84bed44SXin Long netif_keep_dst(dev);
135084e54fe0SWilliam Tu
135184e54fe0SWilliam Tu return ip_tunnel_init(dev);
135284e54fe0SWilliam Tu }
135384e54fe0SWilliam Tu
135484e54fe0SWilliam Tu static const struct net_device_ops erspan_netdev_ops = {
135584e54fe0SWilliam Tu .ndo_init = erspan_tunnel_init,
135684e54fe0SWilliam Tu .ndo_uninit = ip_tunnel_uninit,
135784e54fe0SWilliam Tu .ndo_start_xmit = erspan_xmit,
135884e54fe0SWilliam Tu .ndo_set_mac_address = eth_mac_addr,
135984e54fe0SWilliam Tu .ndo_validate_addr = eth_validate_addr,
136084e54fe0SWilliam Tu .ndo_change_mtu = ip_tunnel_change_mtu,
136198d7fc46SHeiner Kallweit .ndo_get_stats64 = dev_get_tstats64,
136284e54fe0SWilliam Tu .ndo_get_iflink = ip_tunnel_get_iflink,
136384e54fe0SWilliam Tu .ndo_fill_metadata_dst = gre_fill_metadata_dst,
136484e54fe0SWilliam Tu };
136584e54fe0SWilliam Tu
ipgre_tap_setup(struct net_device * dev)1366e1a80002SHerbert Xu static void ipgre_tap_setup(struct net_device *dev)
1367e1a80002SHerbert Xu {
1368e1a80002SHerbert Xu ether_setup(dev);
1369cfddd4c3SXin Long dev->max_mtu = 0;
1370c5441932SPravin B Shelar dev->netdev_ops = &gre_tap_netdev_ops;
1371d13b161cSJiri Benc dev->priv_flags &= ~IFF_TX_SKB_SHARING;
1372f8c1b7ceSstephen hemminger dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
1373c5441932SPravin B Shelar ip_tunnel_setup(dev, gre_tap_net_id);
1374e1a80002SHerbert Xu }
1375e1a80002SHerbert Xu
1376e1f8f78fSPetr Machata static int
ipgre_newlink_encap_setup(struct net_device * dev,struct nlattr * data[])1377e1f8f78fSPetr Machata ipgre_newlink_encap_setup(struct net_device *dev, struct nlattr *data[])
1378c19e654dSHerbert Xu {
13794565e991STom Herbert struct ip_tunnel_encap ipencap;
13804565e991STom Herbert
13814565e991STom Herbert if (ipgre_netlink_encap_parms(data, &ipencap)) {
13824565e991STom Herbert struct ip_tunnel *t = netdev_priv(dev);
1383e1f8f78fSPetr Machata int err = ip_tunnel_encap_setup(t, &ipencap);
13844565e991STom Herbert
13854565e991STom Herbert if (err < 0)
13864565e991STom Herbert return err;
13874565e991STom Herbert }
1388c19e654dSHerbert Xu
1389e1f8f78fSPetr Machata return 0;
1390e1f8f78fSPetr Machata }
1391e1f8f78fSPetr Machata
ipgre_newlink(struct net * src_net,struct net_device * dev,struct nlattr * tb[],struct nlattr * data[],struct netlink_ext_ack * extack)1392e1f8f78fSPetr Machata static int ipgre_newlink(struct net *src_net, struct net_device *dev,
1393e1f8f78fSPetr Machata struct nlattr *tb[], struct nlattr *data[],
1394e1f8f78fSPetr Machata struct netlink_ext_ack *extack)
1395e1f8f78fSPetr Machata {
1396117aef12SAlexander Lobakin struct ip_tunnel_parm_kern p;
1397e1f8f78fSPetr Machata __u32 fwmark = 0;
1398e1f8f78fSPetr Machata int err;
1399e1f8f78fSPetr Machata
1400e1f8f78fSPetr Machata err = ipgre_newlink_encap_setup(dev, data);
1401e1f8f78fSPetr Machata if (err)
1402e1f8f78fSPetr Machata return err;
1403e1f8f78fSPetr Machata
14049830ad4cSCraig Gallek err = ipgre_netlink_parms(dev, data, tb, &p, &fwmark);
140522a59be8SPhilip Prindeville if (err < 0)
140622a59be8SPhilip Prindeville return err;
14079830ad4cSCraig Gallek return ip_tunnel_newlink(dev, tb, &p, fwmark);
1408c19e654dSHerbert Xu }
1409c19e654dSHerbert Xu
erspan_newlink(struct net * src_net,struct net_device * dev,struct nlattr * tb[],struct nlattr * data[],struct netlink_ext_ack * extack)1410e1f8f78fSPetr Machata static int erspan_newlink(struct net *src_net, struct net_device *dev,
1411e1f8f78fSPetr Machata struct nlattr *tb[], struct nlattr *data[],
1412e1f8f78fSPetr Machata struct netlink_ext_ack *extack)
1413e1f8f78fSPetr Machata {
1414117aef12SAlexander Lobakin struct ip_tunnel_parm_kern p;
1415e1f8f78fSPetr Machata __u32 fwmark = 0;
1416e1f8f78fSPetr Machata int err;
1417e1f8f78fSPetr Machata
1418e1f8f78fSPetr Machata err = ipgre_newlink_encap_setup(dev, data);
1419e1f8f78fSPetr Machata if (err)
1420e1f8f78fSPetr Machata return err;
1421e1f8f78fSPetr Machata
1422e1f8f78fSPetr Machata err = erspan_netlink_parms(dev, data, tb, &p, &fwmark);
1423e1f8f78fSPetr Machata if (err)
1424e1f8f78fSPetr Machata return err;
1425e1f8f78fSPetr Machata return ip_tunnel_newlink(dev, tb, &p, fwmark);
1426e1f8f78fSPetr Machata }
1427e1f8f78fSPetr Machata
ipgre_changelink(struct net_device * dev,struct nlattr * tb[],struct nlattr * data[],struct netlink_ext_ack * extack)1428c19e654dSHerbert Xu static int ipgre_changelink(struct net_device *dev, struct nlattr *tb[],
1429ad744b22SMatthias Schiffer struct nlattr *data[],
1430ad744b22SMatthias Schiffer struct netlink_ext_ack *extack)
1431c19e654dSHerbert Xu {
14329830ad4cSCraig Gallek struct ip_tunnel *t = netdev_priv(dev);
1433117aef12SAlexander Lobakin struct ip_tunnel_parm_kern p;
14349830ad4cSCraig Gallek __u32 fwmark = t->fwmark;
143522a59be8SPhilip Prindeville int err;
14364565e991STom Herbert
1437e1f8f78fSPetr Machata err = ipgre_newlink_encap_setup(dev, data);
1438e1f8f78fSPetr Machata if (err)
14394565e991STom Herbert return err;
1440c19e654dSHerbert Xu
14419830ad4cSCraig Gallek err = ipgre_netlink_parms(dev, data, tb, &p, &fwmark);
144222a59be8SPhilip Prindeville if (err < 0)
144322a59be8SPhilip Prindeville return err;
1444dd9d598cSXin Long
1445dd9d598cSXin Long err = ip_tunnel_changelink(dev, tb, &p, fwmark);
1446dd9d598cSXin Long if (err < 0)
1447dd9d598cSXin Long return err;
1448dd9d598cSXin Long
14495832c4a7SAlexander Lobakin ip_tunnel_flags_copy(t->parms.i_flags, p.i_flags);
14505832c4a7SAlexander Lobakin ip_tunnel_flags_copy(t->parms.o_flags, p.o_flags);
1451dd9d598cSXin Long
1452dd9d598cSXin Long ipgre_link_update(dev, !tb[IFLA_MTU]);
1453dd9d598cSXin Long
1454dd9d598cSXin Long return 0;
1455c19e654dSHerbert Xu }
1456c19e654dSHerbert Xu
erspan_changelink(struct net_device * dev,struct nlattr * tb[],struct nlattr * data[],struct netlink_ext_ack * extack)1457e1f8f78fSPetr Machata static int erspan_changelink(struct net_device *dev, struct nlattr *tb[],
1458e1f8f78fSPetr Machata struct nlattr *data[],
1459e1f8f78fSPetr Machata struct netlink_ext_ack *extack)
1460e1f8f78fSPetr Machata {
1461e1f8f78fSPetr Machata struct ip_tunnel *t = netdev_priv(dev);
1462117aef12SAlexander Lobakin struct ip_tunnel_parm_kern p;
1463e1f8f78fSPetr Machata __u32 fwmark = t->fwmark;
1464e1f8f78fSPetr Machata int err;
1465e1f8f78fSPetr Machata
1466e1f8f78fSPetr Machata err = ipgre_newlink_encap_setup(dev, data);
1467e1f8f78fSPetr Machata if (err)
1468e1f8f78fSPetr Machata return err;
1469e1f8f78fSPetr Machata
1470e1f8f78fSPetr Machata err = erspan_netlink_parms(dev, data, tb, &p, &fwmark);
1471e1f8f78fSPetr Machata if (err < 0)
1472e1f8f78fSPetr Machata return err;
1473e1f8f78fSPetr Machata
1474e1f8f78fSPetr Machata err = ip_tunnel_changelink(dev, tb, &p, fwmark);
1475e1f8f78fSPetr Machata if (err < 0)
1476e1f8f78fSPetr Machata return err;
1477e1f8f78fSPetr Machata
14785832c4a7SAlexander Lobakin ip_tunnel_flags_copy(t->parms.i_flags, p.i_flags);
14795832c4a7SAlexander Lobakin ip_tunnel_flags_copy(t->parms.o_flags, p.o_flags);
1480e1f8f78fSPetr Machata
1481e1f8f78fSPetr Machata return 0;
1482e1f8f78fSPetr Machata }
1483e1f8f78fSPetr Machata
ipgre_get_size(const struct net_device * dev)1484c19e654dSHerbert Xu static size_t ipgre_get_size(const struct net_device *dev)
1485c19e654dSHerbert Xu {
1486c19e654dSHerbert Xu return
1487c19e654dSHerbert Xu /* IFLA_GRE_LINK */
1488c19e654dSHerbert Xu nla_total_size(4) +
1489c19e654dSHerbert Xu /* IFLA_GRE_IFLAGS */
1490c19e654dSHerbert Xu nla_total_size(2) +
1491c19e654dSHerbert Xu /* IFLA_GRE_OFLAGS */
1492c19e654dSHerbert Xu nla_total_size(2) +
1493c19e654dSHerbert Xu /* IFLA_GRE_IKEY */
1494c19e654dSHerbert Xu nla_total_size(4) +
1495c19e654dSHerbert Xu /* IFLA_GRE_OKEY */
1496c19e654dSHerbert Xu nla_total_size(4) +
1497c19e654dSHerbert Xu /* IFLA_GRE_LOCAL */
1498c19e654dSHerbert Xu nla_total_size(4) +
1499c19e654dSHerbert Xu /* IFLA_GRE_REMOTE */
1500c19e654dSHerbert Xu nla_total_size(4) +
1501c19e654dSHerbert Xu /* IFLA_GRE_TTL */
1502c19e654dSHerbert Xu nla_total_size(1) +
1503c19e654dSHerbert Xu /* IFLA_GRE_TOS */
1504c19e654dSHerbert Xu nla_total_size(1) +
1505c19e654dSHerbert Xu /* IFLA_GRE_PMTUDISC */
1506c19e654dSHerbert Xu nla_total_size(1) +
15074565e991STom Herbert /* IFLA_GRE_ENCAP_TYPE */
15084565e991STom Herbert nla_total_size(2) +
15094565e991STom Herbert /* IFLA_GRE_ENCAP_FLAGS */
15104565e991STom Herbert nla_total_size(2) +
15114565e991STom Herbert /* IFLA_GRE_ENCAP_SPORT */
15124565e991STom Herbert nla_total_size(2) +
15134565e991STom Herbert /* IFLA_GRE_ENCAP_DPORT */
15144565e991STom Herbert nla_total_size(2) +
15152e15ea39SPravin B Shelar /* IFLA_GRE_COLLECT_METADATA */
15162e15ea39SPravin B Shelar nla_total_size(0) +
151722a59be8SPhilip Prindeville /* IFLA_GRE_IGNORE_DF */
151822a59be8SPhilip Prindeville nla_total_size(1) +
15199830ad4cSCraig Gallek /* IFLA_GRE_FWMARK */
15209830ad4cSCraig Gallek nla_total_size(4) +
152184e54fe0SWilliam Tu /* IFLA_GRE_ERSPAN_INDEX */
152284e54fe0SWilliam Tu nla_total_size(4) +
1523f551c91dSWilliam Tu /* IFLA_GRE_ERSPAN_VER */
1524f551c91dSWilliam Tu nla_total_size(1) +
1525f551c91dSWilliam Tu /* IFLA_GRE_ERSPAN_DIR */
1526f551c91dSWilliam Tu nla_total_size(1) +
1527f551c91dSWilliam Tu /* IFLA_GRE_ERSPAN_HWID */
1528f551c91dSWilliam Tu nla_total_size(2) +
1529c19e654dSHerbert Xu 0;
1530c19e654dSHerbert Xu }
1531c19e654dSHerbert Xu
ipgre_fill_info(struct sk_buff * skb,const struct net_device * dev)1532c19e654dSHerbert Xu static int ipgre_fill_info(struct sk_buff *skb, const struct net_device *dev)
1533c19e654dSHerbert Xu {
1534c19e654dSHerbert Xu struct ip_tunnel *t = netdev_priv(dev);
1535117aef12SAlexander Lobakin struct ip_tunnel_parm_kern *p = &t->parms;
15365832c4a7SAlexander Lobakin IP_TUNNEL_DECLARE_FLAGS(o_flags);
15375832c4a7SAlexander Lobakin
15385832c4a7SAlexander Lobakin ip_tunnel_flags_copy(o_flags, p->o_flags);
1539feaf5c79SLorenzo Bianconi
1540f3756b79SDavid S. Miller if (nla_put_u32(skb, IFLA_GRE_LINK, p->link) ||
154195f5c64cSTom Herbert nla_put_be16(skb, IFLA_GRE_IFLAGS,
154295f5c64cSTom Herbert gre_tnl_flags_to_gre_flags(p->i_flags)) ||
154395f5c64cSTom Herbert nla_put_be16(skb, IFLA_GRE_OFLAGS,
1544feaf5c79SLorenzo Bianconi gre_tnl_flags_to_gre_flags(o_flags)) ||
1545f3756b79SDavid S. Miller nla_put_be32(skb, IFLA_GRE_IKEY, p->i_key) ||
1546f3756b79SDavid S. Miller nla_put_be32(skb, IFLA_GRE_OKEY, p->o_key) ||
1547930345eaSJiri Benc nla_put_in_addr(skb, IFLA_GRE_LOCAL, p->iph.saddr) ||
1548930345eaSJiri Benc nla_put_in_addr(skb, IFLA_GRE_REMOTE, p->iph.daddr) ||
1549f3756b79SDavid S. Miller nla_put_u8(skb, IFLA_GRE_TTL, p->iph.ttl) ||
1550f3756b79SDavid S. Miller nla_put_u8(skb, IFLA_GRE_TOS, p->iph.tos) ||
1551f3756b79SDavid S. Miller nla_put_u8(skb, IFLA_GRE_PMTUDISC,
15529830ad4cSCraig Gallek !!(p->iph.frag_off & htons(IP_DF))) ||
15539830ad4cSCraig Gallek nla_put_u32(skb, IFLA_GRE_FWMARK, t->fwmark))
1554f3756b79SDavid S. Miller goto nla_put_failure;
15554565e991STom Herbert
15564565e991STom Herbert if (nla_put_u16(skb, IFLA_GRE_ENCAP_TYPE,
15574565e991STom Herbert t->encap.type) ||
15583e97fa70SSabrina Dubroca nla_put_be16(skb, IFLA_GRE_ENCAP_SPORT,
15594565e991STom Herbert t->encap.sport) ||
15603e97fa70SSabrina Dubroca nla_put_be16(skb, IFLA_GRE_ENCAP_DPORT,
15614565e991STom Herbert t->encap.dport) ||
15624565e991STom Herbert nla_put_u16(skb, IFLA_GRE_ENCAP_FLAGS,
1563e1b2cb65STom Herbert t->encap.flags))
15644565e991STom Herbert goto nla_put_failure;
15654565e991STom Herbert
156622a59be8SPhilip Prindeville if (nla_put_u8(skb, IFLA_GRE_IGNORE_DF, t->ignore_df))
156722a59be8SPhilip Prindeville goto nla_put_failure;
156822a59be8SPhilip Prindeville
15692e15ea39SPravin B Shelar if (t->collect_md) {
15702e15ea39SPravin B Shelar if (nla_put_flag(skb, IFLA_GRE_COLLECT_METADATA))
15712e15ea39SPravin B Shelar goto nla_put_failure;
15722e15ea39SPravin B Shelar }
15732e15ea39SPravin B Shelar
1574c19e654dSHerbert Xu return 0;
1575c19e654dSHerbert Xu
1576c19e654dSHerbert Xu nla_put_failure:
1577c19e654dSHerbert Xu return -EMSGSIZE;
1578c19e654dSHerbert Xu }
1579c19e654dSHerbert Xu
erspan_fill_info(struct sk_buff * skb,const struct net_device * dev)1580ee496694SHangbin Liu static int erspan_fill_info(struct sk_buff *skb, const struct net_device *dev)
1581ee496694SHangbin Liu {
1582ee496694SHangbin Liu struct ip_tunnel *t = netdev_priv(dev);
1583ee496694SHangbin Liu
1584ee496694SHangbin Liu if (t->erspan_ver <= 2) {
1585ee496694SHangbin Liu if (t->erspan_ver != 0 && !t->collect_md)
15865832c4a7SAlexander Lobakin __set_bit(IP_TUNNEL_KEY_BIT, t->parms.o_flags);
1587ee496694SHangbin Liu
1588ee496694SHangbin Liu if (nla_put_u8(skb, IFLA_GRE_ERSPAN_VER, t->erspan_ver))
1589ee496694SHangbin Liu goto nla_put_failure;
1590ee496694SHangbin Liu
1591ee496694SHangbin Liu if (t->erspan_ver == 1) {
1592ee496694SHangbin Liu if (nla_put_u32(skb, IFLA_GRE_ERSPAN_INDEX, t->index))
1593ee496694SHangbin Liu goto nla_put_failure;
1594ee496694SHangbin Liu } else if (t->erspan_ver == 2) {
1595ee496694SHangbin Liu if (nla_put_u8(skb, IFLA_GRE_ERSPAN_DIR, t->dir))
1596ee496694SHangbin Liu goto nla_put_failure;
1597ee496694SHangbin Liu if (nla_put_u16(skb, IFLA_GRE_ERSPAN_HWID, t->hwid))
1598ee496694SHangbin Liu goto nla_put_failure;
1599ee496694SHangbin Liu }
1600ee496694SHangbin Liu }
1601ee496694SHangbin Liu
1602ee496694SHangbin Liu return ipgre_fill_info(skb, dev);
1603ee496694SHangbin Liu
1604ee496694SHangbin Liu nla_put_failure:
1605ee496694SHangbin Liu return -EMSGSIZE;
1606ee496694SHangbin Liu }
1607ee496694SHangbin Liu
erspan_setup(struct net_device * dev)160884e54fe0SWilliam Tu static void erspan_setup(struct net_device *dev)
160984e54fe0SWilliam Tu {
161084581bdaSXin Long struct ip_tunnel *t = netdev_priv(dev);
161184581bdaSXin Long
161284e54fe0SWilliam Tu ether_setup(dev);
16130e141f75SHaishuang Yan dev->max_mtu = 0;
161484e54fe0SWilliam Tu dev->netdev_ops = &erspan_netdev_ops;
161584e54fe0SWilliam Tu dev->priv_flags &= ~IFF_TX_SKB_SHARING;
161684e54fe0SWilliam Tu dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
161784e54fe0SWilliam Tu ip_tunnel_setup(dev, erspan_net_id);
161884581bdaSXin Long t->erspan_ver = 1;
161984e54fe0SWilliam Tu }
162084e54fe0SWilliam Tu
1621c19e654dSHerbert Xu static const struct nla_policy ipgre_policy[IFLA_GRE_MAX + 1] = {
1622c19e654dSHerbert Xu [IFLA_GRE_LINK] = { .type = NLA_U32 },
1623c19e654dSHerbert Xu [IFLA_GRE_IFLAGS] = { .type = NLA_U16 },
1624c19e654dSHerbert Xu [IFLA_GRE_OFLAGS] = { .type = NLA_U16 },
1625c19e654dSHerbert Xu [IFLA_GRE_IKEY] = { .type = NLA_U32 },
1626c19e654dSHerbert Xu [IFLA_GRE_OKEY] = { .type = NLA_U32 },
1627c593642cSPankaj Bharadiya [IFLA_GRE_LOCAL] = { .len = sizeof_field(struct iphdr, saddr) },
1628c593642cSPankaj Bharadiya [IFLA_GRE_REMOTE] = { .len = sizeof_field(struct iphdr, daddr) },
1629c19e654dSHerbert Xu [IFLA_GRE_TTL] = { .type = NLA_U8 },
1630c19e654dSHerbert Xu [IFLA_GRE_TOS] = { .type = NLA_U8 },
1631c19e654dSHerbert Xu [IFLA_GRE_PMTUDISC] = { .type = NLA_U8 },
16324565e991STom Herbert [IFLA_GRE_ENCAP_TYPE] = { .type = NLA_U16 },
16334565e991STom Herbert [IFLA_GRE_ENCAP_FLAGS] = { .type = NLA_U16 },
16344565e991STom Herbert [IFLA_GRE_ENCAP_SPORT] = { .type = NLA_U16 },
16354565e991STom Herbert [IFLA_GRE_ENCAP_DPORT] = { .type = NLA_U16 },
16362e15ea39SPravin B Shelar [IFLA_GRE_COLLECT_METADATA] = { .type = NLA_FLAG },
163722a59be8SPhilip Prindeville [IFLA_GRE_IGNORE_DF] = { .type = NLA_U8 },
16389830ad4cSCraig Gallek [IFLA_GRE_FWMARK] = { .type = NLA_U32 },
163984e54fe0SWilliam Tu [IFLA_GRE_ERSPAN_INDEX] = { .type = NLA_U32 },
1640f551c91dSWilliam Tu [IFLA_GRE_ERSPAN_VER] = { .type = NLA_U8 },
1641f551c91dSWilliam Tu [IFLA_GRE_ERSPAN_DIR] = { .type = NLA_U8 },
1642f551c91dSWilliam Tu [IFLA_GRE_ERSPAN_HWID] = { .type = NLA_U16 },
1643c19e654dSHerbert Xu };
1644c19e654dSHerbert Xu
1645c19e654dSHerbert Xu static struct rtnl_link_ops ipgre_link_ops __read_mostly = {
1646c19e654dSHerbert Xu .kind = "gre",
1647c19e654dSHerbert Xu .maxtype = IFLA_GRE_MAX,
1648c19e654dSHerbert Xu .policy = ipgre_policy,
1649c19e654dSHerbert Xu .priv_size = sizeof(struct ip_tunnel),
1650c19e654dSHerbert Xu .setup = ipgre_tunnel_setup,
1651c19e654dSHerbert Xu .validate = ipgre_tunnel_validate,
1652c19e654dSHerbert Xu .newlink = ipgre_newlink,
1653c19e654dSHerbert Xu .changelink = ipgre_changelink,
1654c5441932SPravin B Shelar .dellink = ip_tunnel_dellink,
1655c19e654dSHerbert Xu .get_size = ipgre_get_size,
1656c19e654dSHerbert Xu .fill_info = ipgre_fill_info,
16571728d4faSNicolas Dichtel .get_link_net = ip_tunnel_get_link_net,
1658c19e654dSHerbert Xu };
1659c19e654dSHerbert Xu
1660e1a80002SHerbert Xu static struct rtnl_link_ops ipgre_tap_ops __read_mostly = {
1661e1a80002SHerbert Xu .kind = "gretap",
1662e1a80002SHerbert Xu .maxtype = IFLA_GRE_MAX,
1663e1a80002SHerbert Xu .policy = ipgre_policy,
1664e1a80002SHerbert Xu .priv_size = sizeof(struct ip_tunnel),
1665e1a80002SHerbert Xu .setup = ipgre_tap_setup,
1666e1a80002SHerbert Xu .validate = ipgre_tap_validate,
1667e1a80002SHerbert Xu .newlink = ipgre_newlink,
1668e1a80002SHerbert Xu .changelink = ipgre_changelink,
1669c5441932SPravin B Shelar .dellink = ip_tunnel_dellink,
1670e1a80002SHerbert Xu .get_size = ipgre_get_size,
1671e1a80002SHerbert Xu .fill_info = ipgre_fill_info,
16721728d4faSNicolas Dichtel .get_link_net = ip_tunnel_get_link_net,
1673e1a80002SHerbert Xu };
1674e1a80002SHerbert Xu
167584e54fe0SWilliam Tu static struct rtnl_link_ops erspan_link_ops __read_mostly = {
167684e54fe0SWilliam Tu .kind = "erspan",
167784e54fe0SWilliam Tu .maxtype = IFLA_GRE_MAX,
167884e54fe0SWilliam Tu .policy = ipgre_policy,
167984e54fe0SWilliam Tu .priv_size = sizeof(struct ip_tunnel),
168084e54fe0SWilliam Tu .setup = erspan_setup,
168184e54fe0SWilliam Tu .validate = erspan_validate,
1682e1f8f78fSPetr Machata .newlink = erspan_newlink,
1683e1f8f78fSPetr Machata .changelink = erspan_changelink,
168484e54fe0SWilliam Tu .dellink = ip_tunnel_dellink,
168584e54fe0SWilliam Tu .get_size = ipgre_get_size,
1686ee496694SHangbin Liu .fill_info = erspan_fill_info,
168784e54fe0SWilliam Tu .get_link_net = ip_tunnel_get_link_net,
168884e54fe0SWilliam Tu };
168984e54fe0SWilliam Tu
gretap_fb_dev_create(struct net * net,const char * name,u8 name_assign_type)1690b2acd1dcSPravin B Shelar struct net_device *gretap_fb_dev_create(struct net *net, const char *name,
1691b2acd1dcSPravin B Shelar u8 name_assign_type)
1692b2acd1dcSPravin B Shelar {
1693b2acd1dcSPravin B Shelar struct nlattr *tb[IFLA_MAX + 1];
1694b2acd1dcSPravin B Shelar struct net_device *dev;
1695106da663SNicolas Dichtel LIST_HEAD(list_kill);
1696b2acd1dcSPravin B Shelar struct ip_tunnel *t;
1697b2acd1dcSPravin B Shelar int err;
1698b2acd1dcSPravin B Shelar
1699b2acd1dcSPravin B Shelar memset(&tb, 0, sizeof(tb));
1700b2acd1dcSPravin B Shelar
1701b2acd1dcSPravin B Shelar dev = rtnl_create_link(net, name, name_assign_type,
1702d0522f1cSDavid Ahern &ipgre_tap_ops, tb, NULL);
1703b2acd1dcSPravin B Shelar if (IS_ERR(dev))
1704b2acd1dcSPravin B Shelar return dev;
1705b2acd1dcSPravin B Shelar
1706b2acd1dcSPravin B Shelar /* Configure flow based GRE device. */
1707b2acd1dcSPravin B Shelar t = netdev_priv(dev);
1708b2acd1dcSPravin B Shelar t->collect_md = true;
1709b2acd1dcSPravin B Shelar
17107a3f4a18SMatthias Schiffer err = ipgre_newlink(net, dev, tb, NULL, NULL);
1711106da663SNicolas Dichtel if (err < 0) {
1712106da663SNicolas Dichtel free_netdev(dev);
1713106da663SNicolas Dichtel return ERR_PTR(err);
1714106da663SNicolas Dichtel }
17157e059158SDavid Wragg
17167e059158SDavid Wragg /* openvswitch users expect packet sizes to be unrestricted,
17177e059158SDavid Wragg * so set the largest MTU we can.
17187e059158SDavid Wragg */
17197e059158SDavid Wragg err = __ip_tunnel_change_mtu(dev, IP_MAX_MTU, false);
17207e059158SDavid Wragg if (err)
17217e059158SDavid Wragg goto out;
17227e059158SDavid Wragg
17231d997f10SHangbin Liu err = rtnl_configure_link(dev, NULL, 0, NULL);
1724da6f1da8SNicolas Dichtel if (err < 0)
1725da6f1da8SNicolas Dichtel goto out;
1726da6f1da8SNicolas Dichtel
1727b2acd1dcSPravin B Shelar return dev;
1728b2acd1dcSPravin B Shelar out:
1729106da663SNicolas Dichtel ip_tunnel_dellink(dev, &list_kill);
1730106da663SNicolas Dichtel unregister_netdevice_many(&list_kill);
1731b2acd1dcSPravin B Shelar return ERR_PTR(err);
1732b2acd1dcSPravin B Shelar }
1733b2acd1dcSPravin B Shelar EXPORT_SYMBOL_GPL(gretap_fb_dev_create);
1734b2acd1dcSPravin B Shelar
ipgre_tap_init_net(struct net * net)1735c5441932SPravin B Shelar static int __net_init ipgre_tap_init_net(struct net *net)
1736c5441932SPravin B Shelar {
17372e15ea39SPravin B Shelar return ip_tunnel_init_net(net, gre_tap_net_id, &ipgre_tap_ops, "gretap0");
1738c5441932SPravin B Shelar }
1739c5441932SPravin B Shelar
ipgre_tap_exit_batch_rtnl(struct list_head * list_net,struct list_head * dev_to_kill)17409b5b3637SEric Dumazet static void __net_exit ipgre_tap_exit_batch_rtnl(struct list_head *list_net,
17419b5b3637SEric Dumazet struct list_head *dev_to_kill)
1742c5441932SPravin B Shelar {
17439b5b3637SEric Dumazet ip_tunnel_delete_nets(list_net, gre_tap_net_id, &ipgre_tap_ops,
17449b5b3637SEric Dumazet dev_to_kill);
1745c5441932SPravin B Shelar }
1746c5441932SPravin B Shelar
1747c5441932SPravin B Shelar static struct pernet_operations ipgre_tap_net_ops = {
1748c5441932SPravin B Shelar .init = ipgre_tap_init_net,
17499b5b3637SEric Dumazet .exit_batch_rtnl = ipgre_tap_exit_batch_rtnl,
1750c5441932SPravin B Shelar .id = &gre_tap_net_id,
1751c5441932SPravin B Shelar .size = sizeof(struct ip_tunnel_net),
1752c5441932SPravin B Shelar };
17531da177e4SLinus Torvalds
erspan_init_net(struct net * net)175484e54fe0SWilliam Tu static int __net_init erspan_init_net(struct net *net)
175584e54fe0SWilliam Tu {
175684e54fe0SWilliam Tu return ip_tunnel_init_net(net, erspan_net_id,
175784e54fe0SWilliam Tu &erspan_link_ops, "erspan0");
175884e54fe0SWilliam Tu }
175984e54fe0SWilliam Tu
erspan_exit_batch_rtnl(struct list_head * net_list,struct list_head * dev_to_kill)17609b5b3637SEric Dumazet static void __net_exit erspan_exit_batch_rtnl(struct list_head *net_list,
17619b5b3637SEric Dumazet struct list_head *dev_to_kill)
176284e54fe0SWilliam Tu {
17639b5b3637SEric Dumazet ip_tunnel_delete_nets(net_list, erspan_net_id, &erspan_link_ops,
17649b5b3637SEric Dumazet dev_to_kill);
176584e54fe0SWilliam Tu }
176684e54fe0SWilliam Tu
176784e54fe0SWilliam Tu static struct pernet_operations erspan_net_ops = {
176884e54fe0SWilliam Tu .init = erspan_init_net,
17699b5b3637SEric Dumazet .exit_batch_rtnl = erspan_exit_batch_rtnl,
177084e54fe0SWilliam Tu .id = &erspan_net_id,
177184e54fe0SWilliam Tu .size = sizeof(struct ip_tunnel_net),
177284e54fe0SWilliam Tu };
177384e54fe0SWilliam Tu
ipgre_init(void)17741da177e4SLinus Torvalds static int __init ipgre_init(void)
17751da177e4SLinus Torvalds {
17761da177e4SLinus Torvalds int err;
17771da177e4SLinus Torvalds
1778058bd4d2SJoe Perches pr_info("GRE over IPv4 tunneling driver\n");
17791da177e4SLinus Torvalds
1780cfb8fbf2SEric W. Biederman err = register_pernet_device(&ipgre_net_ops);
178159a4c759SPavel Emelyanov if (err < 0)
1782c2892f02SAlexey Dobriyan return err;
1783c2892f02SAlexey Dobriyan
1784c5441932SPravin B Shelar err = register_pernet_device(&ipgre_tap_net_ops);
1785c5441932SPravin B Shelar if (err < 0)
1786e3d0328cSWilliam Tu goto pnet_tap_failed;
1787c5441932SPravin B Shelar
178884e54fe0SWilliam Tu err = register_pernet_device(&erspan_net_ops);
178984e54fe0SWilliam Tu if (err < 0)
179084e54fe0SWilliam Tu goto pnet_erspan_failed;
179184e54fe0SWilliam Tu
17929f57c67cSPravin B Shelar err = gre_add_protocol(&ipgre_protocol, GREPROTO_CISCO);
1793c2892f02SAlexey Dobriyan if (err < 0) {
1794058bd4d2SJoe Perches pr_info("%s: can't add protocol\n", __func__);
1795c2892f02SAlexey Dobriyan goto add_proto_failed;
1796c2892f02SAlexey Dobriyan }
17977daa0004SPavel Emelyanov
1798c19e654dSHerbert Xu err = rtnl_link_register(&ipgre_link_ops);
1799c19e654dSHerbert Xu if (err < 0)
1800c19e654dSHerbert Xu goto rtnl_link_failed;
1801c19e654dSHerbert Xu
1802e1a80002SHerbert Xu err = rtnl_link_register(&ipgre_tap_ops);
1803e1a80002SHerbert Xu if (err < 0)
1804e1a80002SHerbert Xu goto tap_ops_failed;
1805e1a80002SHerbert Xu
180684e54fe0SWilliam Tu err = rtnl_link_register(&erspan_link_ops);
180784e54fe0SWilliam Tu if (err < 0)
180884e54fe0SWilliam Tu goto erspan_link_failed;
180984e54fe0SWilliam Tu
1810c5441932SPravin B Shelar return 0;
1811c19e654dSHerbert Xu
181284e54fe0SWilliam Tu erspan_link_failed:
181384e54fe0SWilliam Tu rtnl_link_unregister(&ipgre_tap_ops);
1814e1a80002SHerbert Xu tap_ops_failed:
1815e1a80002SHerbert Xu rtnl_link_unregister(&ipgre_link_ops);
1816c19e654dSHerbert Xu rtnl_link_failed:
18179f57c67cSPravin B Shelar gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO);
1818c2892f02SAlexey Dobriyan add_proto_failed:
181984e54fe0SWilliam Tu unregister_pernet_device(&erspan_net_ops);
182084e54fe0SWilliam Tu pnet_erspan_failed:
1821c5441932SPravin B Shelar unregister_pernet_device(&ipgre_tap_net_ops);
1822e3d0328cSWilliam Tu pnet_tap_failed:
1823c2892f02SAlexey Dobriyan unregister_pernet_device(&ipgre_net_ops);
1824c5441932SPravin B Shelar return err;
18251da177e4SLinus Torvalds }
18261da177e4SLinus Torvalds
ipgre_fini(void)1827db44575fSAlexey Kuznetsov static void __exit ipgre_fini(void)
18281da177e4SLinus Torvalds {
1829e1a80002SHerbert Xu rtnl_link_unregister(&ipgre_tap_ops);
1830c19e654dSHerbert Xu rtnl_link_unregister(&ipgre_link_ops);
183184e54fe0SWilliam Tu rtnl_link_unregister(&erspan_link_ops);
18329f57c67cSPravin B Shelar gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO);
1833c5441932SPravin B Shelar unregister_pernet_device(&ipgre_tap_net_ops);
1834c2892f02SAlexey Dobriyan unregister_pernet_device(&ipgre_net_ops);
183584e54fe0SWilliam Tu unregister_pernet_device(&erspan_net_ops);
18361da177e4SLinus Torvalds }
18371da177e4SLinus Torvalds
18381da177e4SLinus Torvalds module_init(ipgre_init);
18391da177e4SLinus Torvalds module_exit(ipgre_fini);
1840b058a5d2SBreno Leitao MODULE_DESCRIPTION("IPv4 GRE tunnels over IP library");
18411da177e4SLinus Torvalds MODULE_LICENSE("GPL");
18424d74f8baSPatrick McHardy MODULE_ALIAS_RTNL_LINK("gre");
18434d74f8baSPatrick McHardy MODULE_ALIAS_RTNL_LINK("gretap");
184484e54fe0SWilliam Tu MODULE_ALIAS_RTNL_LINK("erspan");
18458909c9adSVasiliy Kulikov MODULE_ALIAS_NETDEV("gre0");
1846c5441932SPravin B Shelar MODULE_ALIAS_NETDEV("gretap0");
184784e54fe0SWilliam Tu MODULE_ALIAS_NETDEV("erspan0");
1848