12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 21da177e4SLinus Torvalds /* 31da177e4SLinus Torvalds * Linux NET3: GRE over IP protocol decoder. 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * Authors: Alexey Kuznetsov (kuznet@ms2.inr.ac.ru) 61da177e4SLinus Torvalds */ 71da177e4SLinus Torvalds 8afd46503SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 9afd46503SJoe Perches 104fc268d2SRandy Dunlap #include <linux/capability.h> 111da177e4SLinus Torvalds #include <linux/module.h> 121da177e4SLinus Torvalds #include <linux/types.h> 131da177e4SLinus Torvalds #include <linux/kernel.h> 145a0e3ad6STejun Heo #include <linux/slab.h> 157c0f6ba6SLinus Torvalds #include <linux/uaccess.h> 161da177e4SLinus Torvalds #include <linux/skbuff.h> 171da177e4SLinus Torvalds #include <linux/netdevice.h> 181da177e4SLinus Torvalds #include <linux/in.h> 191da177e4SLinus Torvalds #include <linux/tcp.h> 201da177e4SLinus Torvalds #include <linux/udp.h> 211da177e4SLinus Torvalds #include <linux/if_arp.h> 222e15ea39SPravin B Shelar #include <linux/if_vlan.h> 231da177e4SLinus Torvalds #include <linux/init.h> 241da177e4SLinus Torvalds #include <linux/in6.h> 251da177e4SLinus Torvalds #include <linux/inetdevice.h> 261da177e4SLinus Torvalds #include <linux/igmp.h> 271da177e4SLinus Torvalds #include <linux/netfilter_ipv4.h> 28e1a80002SHerbert Xu #include <linux/etherdevice.h> 2946f25dffSKris Katterjohn #include <linux/if_ether.h> 301da177e4SLinus Torvalds 311da177e4SLinus Torvalds #include <net/sock.h> 321da177e4SLinus Torvalds #include <net/ip.h> 331da177e4SLinus Torvalds #include <net/icmp.h> 341da177e4SLinus Torvalds #include <net/protocol.h> 35c5441932SPravin B Shelar #include <net/ip_tunnels.h> 361da177e4SLinus Torvalds #include <net/arp.h> 371da177e4SLinus Torvalds #include <net/checksum.h> 381da177e4SLinus Torvalds #include <net/dsfield.h> 391da177e4SLinus Torvalds #include <net/inet_ecn.h> 401da177e4SLinus Torvalds #include <net/xfrm.h> 4159a4c759SPavel Emelyanov #include <net/net_namespace.h> 4259a4c759SPavel Emelyanov #include <net/netns/generic.h> 43c19e654dSHerbert Xu #include <net/rtnetlink.h> 4400959adeSDmitry Kozlov #include <net/gre.h> 452e15ea39SPravin B Shelar #include <net/dst_metadata.h> 4684e54fe0SWilliam Tu #include <net/erspan.h> 471da177e4SLinus Torvalds 481da177e4SLinus Torvalds /* 491da177e4SLinus Torvalds Problems & solutions 501da177e4SLinus Torvalds -------------------- 511da177e4SLinus Torvalds 521da177e4SLinus Torvalds 1. The most important issue is detecting local dead loops. 531da177e4SLinus Torvalds They would cause complete host lockup in transmit, which 541da177e4SLinus Torvalds would be "resolved" by stack overflow or, if queueing is enabled, 551da177e4SLinus Torvalds with infinite looping in net_bh. 561da177e4SLinus Torvalds 571da177e4SLinus Torvalds We cannot track such dead loops during route installation, 581da177e4SLinus Torvalds it is infeasible task. The most general solutions would be 591da177e4SLinus Torvalds to keep skb->encapsulation counter (sort of local ttl), 606d0722a2SEric Dumazet and silently drop packet when it expires. It is a good 61bff52857Sstephen hemminger solution, but it supposes maintaining new variable in ALL 621da177e4SLinus Torvalds skb, even if no tunneling is used. 631da177e4SLinus Torvalds 646d0722a2SEric Dumazet Current solution: xmit_recursion breaks dead loops. This is a percpu 656d0722a2SEric Dumazet counter, since when we enter the first ndo_xmit(), cpu migration is 666d0722a2SEric Dumazet forbidden. We force an exit if this counter reaches RECURSION_LIMIT 671da177e4SLinus Torvalds 681da177e4SLinus Torvalds 2. Networking dead loops would not kill routers, but would really 691da177e4SLinus Torvalds kill network. IP hop limit plays role of "t->recursion" in this case, 701da177e4SLinus Torvalds if we copy it from packet being encapsulated to upper header. 711da177e4SLinus Torvalds It is very good solution, but it introduces two problems: 721da177e4SLinus Torvalds 731da177e4SLinus Torvalds - Routing protocols, using packets with ttl=1 (OSPF, RIP2), 741da177e4SLinus Torvalds do not work over tunnels. 751da177e4SLinus Torvalds - traceroute does not work. I planned to relay ICMP from tunnel, 761da177e4SLinus Torvalds so that this problem would be solved and traceroute output 771da177e4SLinus Torvalds would even more informative. This idea appeared to be wrong: 781da177e4SLinus Torvalds only Linux complies to rfc1812 now (yes, guys, Linux is the only 791da177e4SLinus Torvalds true router now :-)), all routers (at least, in neighbourhood of mine) 801da177e4SLinus Torvalds return only 8 bytes of payload. It is the end. 811da177e4SLinus Torvalds 821da177e4SLinus Torvalds Hence, if we want that OSPF worked or traceroute said something reasonable, 831da177e4SLinus Torvalds we should search for another solution. 841da177e4SLinus Torvalds 851da177e4SLinus Torvalds One of them is to parse packet trying to detect inner encapsulation 861da177e4SLinus Torvalds made by our node. It is difficult or even impossible, especially, 87bff52857Sstephen hemminger taking into account fragmentation. TO be short, ttl is not solution at all. 881da177e4SLinus Torvalds 891da177e4SLinus Torvalds Current solution: The solution was UNEXPECTEDLY SIMPLE. 901da177e4SLinus Torvalds We force DF flag on tunnels with preconfigured hop limit, 911da177e4SLinus Torvalds that is ALL. :-) Well, it does not remove the problem completely, 921da177e4SLinus Torvalds but exponential growth of network traffic is changed to linear 931da177e4SLinus Torvalds (branches, that exceed pmtu are pruned) and tunnel mtu 94bff52857Sstephen hemminger rapidly degrades to value <68, where looping stops. 951da177e4SLinus Torvalds Yes, it is not good if there exists a router in the loop, 961da177e4SLinus Torvalds which does not force DF, even when encapsulating packets have DF set. 971da177e4SLinus Torvalds But it is not our problem! Nobody could accuse us, we made 981da177e4SLinus Torvalds all that we could make. Even if it is your gated who injected 991da177e4SLinus Torvalds fatal route to network, even if it were you who configured 1001da177e4SLinus Torvalds fatal static route: you are innocent. :-) 1011da177e4SLinus Torvalds 1021da177e4SLinus Torvalds Alexey Kuznetsov. 1031da177e4SLinus Torvalds */ 1041da177e4SLinus Torvalds 105eccc1bb8Sstephen hemminger static bool log_ecn_error = true; 106eccc1bb8Sstephen hemminger module_param(log_ecn_error, bool, 0644); 107eccc1bb8Sstephen hemminger MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN"); 108eccc1bb8Sstephen hemminger 109c19e654dSHerbert Xu static struct rtnl_link_ops ipgre_link_ops __read_mostly; 110aab1e898SGuillaume Nault static const struct header_ops ipgre_header_ops; 111aab1e898SGuillaume Nault 1121da177e4SLinus Torvalds static int ipgre_tunnel_init(struct net_device *dev); 1131a66a836SWilliam Tu static void erspan_build_header(struct sk_buff *skb, 114c69de58bSWilliam Tu u32 id, u32 index, 115a3222dc9SWilliam Tu bool truncate, bool is_ipv4); 116eb8ce741SPavel Emelyanov 117c7d03a00SAlexey Dobriyan static unsigned int ipgre_net_id __read_mostly; 118c7d03a00SAlexey Dobriyan static unsigned int gre_tap_net_id __read_mostly; 11984e54fe0SWilliam Tu static unsigned int erspan_net_id __read_mostly; 120eb8ce741SPavel Emelyanov 12132bbd879SStefano Brivio static int ipgre_err(struct sk_buff *skb, u32 info, 122bda7bb46SPravin B Shelar const struct tnl_ptk_info *tpi) 1231da177e4SLinus Torvalds { 1241da177e4SLinus Torvalds 125071f92d0SRami Rosen /* All the routers (except for Linux) return only 1261da177e4SLinus Torvalds 8 bytes of packet payload. It means, that precise relaying of 1271da177e4SLinus Torvalds ICMP in the real Internet is absolutely infeasible. 1281da177e4SLinus Torvalds 1291da177e4SLinus Torvalds Moreover, Cisco "wise men" put GRE key to the third word 130c5441932SPravin B Shelar in GRE header. It makes impossible maintaining even soft 131c5441932SPravin B Shelar state for keyed GRE tunnels with enabled checksum. Tell 132c5441932SPravin B Shelar them "thank you". 1331da177e4SLinus Torvalds 1341da177e4SLinus Torvalds Well, I wonder, rfc1812 was written by Cisco employee, 135bff52857Sstephen hemminger what the hell these idiots break standards established 136bff52857Sstephen hemminger by themselves??? 1371da177e4SLinus Torvalds */ 138c5441932SPravin B Shelar struct net *net = dev_net(skb->dev); 139c5441932SPravin B Shelar struct ip_tunnel_net *itn; 14096f5a846SEric Dumazet const struct iphdr *iph; 14188c7664fSArnaldo Carvalho de Melo const int type = icmp_hdr(skb)->type; 14288c7664fSArnaldo Carvalho de Melo const int code = icmp_hdr(skb)->code; 14320e1954fSEric Dumazet unsigned int data_len = 0; 1441da177e4SLinus Torvalds struct ip_tunnel *t; 145d2083287Sstephen hemminger 146bda7bb46SPravin B Shelar if (tpi->proto == htons(ETH_P_TEB)) 147c5441932SPravin B Shelar itn = net_generic(net, gre_tap_net_id); 14851dc63e3SHaishuang Yan else if (tpi->proto == htons(ETH_P_ERSPAN) || 14951dc63e3SHaishuang Yan tpi->proto == htons(ETH_P_ERSPAN2)) 15051dc63e3SHaishuang Yan itn = net_generic(net, erspan_net_id); 151c5441932SPravin B Shelar else 152c5441932SPravin B Shelar itn = net_generic(net, ipgre_net_id); 153c5441932SPravin B Shelar 154c0c0c50fSDuan Jiong iph = (const struct iphdr *)(icmp_hdr(skb) + 1); 155bda7bb46SPravin B Shelar t = ip_tunnel_lookup(itn, skb->dev->ifindex, tpi->flags, 156bda7bb46SPravin B Shelar iph->daddr, iph->saddr, tpi->key); 157d2083287Sstephen hemminger 15851456b29SIan Morris if (!t) 15932bbd879SStefano Brivio return -ENOENT; 16032bbd879SStefano Brivio 16132bbd879SStefano Brivio switch (type) { 16232bbd879SStefano Brivio default: 16332bbd879SStefano Brivio case ICMP_PARAMETERPROB: 16432bbd879SStefano Brivio return 0; 16532bbd879SStefano Brivio 16632bbd879SStefano Brivio case ICMP_DEST_UNREACH: 16732bbd879SStefano Brivio switch (code) { 16832bbd879SStefano Brivio case ICMP_SR_FAILED: 16932bbd879SStefano Brivio case ICMP_PORT_UNREACH: 17032bbd879SStefano Brivio /* Impossible event. */ 17132bbd879SStefano Brivio return 0; 17232bbd879SStefano Brivio default: 17332bbd879SStefano Brivio /* All others are translated to HOST_UNREACH. 17432bbd879SStefano Brivio rfc2003 contains "deep thoughts" about NET_UNREACH, 17532bbd879SStefano Brivio I believe they are just ether pollution. --ANK 17632bbd879SStefano Brivio */ 17732bbd879SStefano Brivio break; 17832bbd879SStefano Brivio } 17932bbd879SStefano Brivio break; 18032bbd879SStefano Brivio 18132bbd879SStefano Brivio case ICMP_TIME_EXCEEDED: 18232bbd879SStefano Brivio if (code != ICMP_EXC_TTL) 18332bbd879SStefano Brivio return 0; 18432bbd879SStefano Brivio data_len = icmp_hdr(skb)->un.reserved[1] * 4; /* RFC 4884 4.1 */ 18532bbd879SStefano Brivio break; 18632bbd879SStefano Brivio 18732bbd879SStefano Brivio case ICMP_REDIRECT: 18832bbd879SStefano Brivio break; 18932bbd879SStefano Brivio } 19036393395SDavid S. Miller 1919b8c6d7bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6) 1929b8c6d7bSEric Dumazet if (tpi->proto == htons(ETH_P_IPV6) && 19320e1954fSEric Dumazet !ip6_err_gen_icmpv6_unreach(skb, iph->ihl * 4 + tpi->hdr_len, 19420e1954fSEric Dumazet type, data_len)) 19532bbd879SStefano Brivio return 0; 1969b8c6d7bSEric Dumazet #endif 1979b8c6d7bSEric Dumazet 19836393395SDavid S. Miller if (t->parms.iph.daddr == 0 || 199f97c1e0cSJoe Perches ipv4_is_multicast(t->parms.iph.daddr)) 20032bbd879SStefano Brivio return 0; 2011da177e4SLinus Torvalds 2021da177e4SLinus Torvalds if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED) 20332bbd879SStefano Brivio return 0; 2041da177e4SLinus Torvalds 205da6185d8SWei Yongjun if (time_before(jiffies, t->err_time + IPTUNNEL_ERR_TIMEO)) 2061da177e4SLinus Torvalds t->err_count++; 2071da177e4SLinus Torvalds else 2081da177e4SLinus Torvalds t->err_count = 1; 2091da177e4SLinus Torvalds t->err_time = jiffies; 21032bbd879SStefano Brivio 21132bbd879SStefano Brivio return 0; 2129f57c67cSPravin B Shelar } 2139f57c67cSPravin B Shelar 2149f57c67cSPravin B Shelar static void gre_err(struct sk_buff *skb, u32 info) 2159f57c67cSPravin B Shelar { 2169f57c67cSPravin B Shelar /* All the routers (except for Linux) return only 2179f57c67cSPravin B Shelar * 8 bytes of packet payload. It means, that precise relaying of 2189f57c67cSPravin B Shelar * ICMP in the real Internet is absolutely infeasible. 2199f57c67cSPravin B Shelar * 2209f57c67cSPravin B Shelar * Moreover, Cisco "wise men" put GRE key to the third word 2219f57c67cSPravin B Shelar * in GRE header. It makes impossible maintaining even soft 2229f57c67cSPravin B Shelar * state for keyed 2239f57c67cSPravin B Shelar * GRE tunnels with enabled checksum. Tell them "thank you". 2249f57c67cSPravin B Shelar * 2259f57c67cSPravin B Shelar * Well, I wonder, rfc1812 was written by Cisco employee, 2269f57c67cSPravin B Shelar * what the hell these idiots break standards established 2279f57c67cSPravin B Shelar * by themselves??? 2289f57c67cSPravin B Shelar */ 2299f57c67cSPravin B Shelar 230e582615aSEric Dumazet const struct iphdr *iph = (struct iphdr *)skb->data; 2319f57c67cSPravin B Shelar const int type = icmp_hdr(skb)->type; 2329f57c67cSPravin B Shelar const int code = icmp_hdr(skb)->code; 2339f57c67cSPravin B Shelar struct tnl_ptk_info tpi; 2349f57c67cSPravin B Shelar 235b0350d51SHaishuang Yan if (gre_parse_header(skb, &tpi, NULL, htons(ETH_P_IP), 236b0350d51SHaishuang Yan iph->ihl * 4) < 0) 2379f57c67cSPravin B Shelar return; 2389f57c67cSPravin B Shelar 2399f57c67cSPravin B Shelar if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) { 2409f57c67cSPravin B Shelar ipv4_update_pmtu(skb, dev_net(skb->dev), info, 241d888f396SMaciej Żenczykowski skb->dev->ifindex, IPPROTO_GRE); 2429f57c67cSPravin B Shelar return; 2439f57c67cSPravin B Shelar } 2449f57c67cSPravin B Shelar if (type == ICMP_REDIRECT) { 2451042caa7SMaciej Żenczykowski ipv4_redirect(skb, dev_net(skb->dev), skb->dev->ifindex, 2461042caa7SMaciej Żenczykowski IPPROTO_GRE); 2479f57c67cSPravin B Shelar return; 2489f57c67cSPravin B Shelar } 2499f57c67cSPravin B Shelar 2509f57c67cSPravin B Shelar ipgre_err(skb, info, &tpi); 2511da177e4SLinus Torvalds } 2521da177e4SLinus Torvalds 253f989d546SWilliam Tu static bool is_erspan_type1(int gre_hdr_len) 254f989d546SWilliam Tu { 255f989d546SWilliam Tu /* Both ERSPAN type I (version 0) and type II (version 1) use 256f989d546SWilliam Tu * protocol 0x88BE, but the type I has only 4-byte GRE header, 257f989d546SWilliam Tu * while type II has 8-byte. 258f989d546SWilliam Tu */ 259f989d546SWilliam Tu return gre_hdr_len == 4; 260f989d546SWilliam Tu } 261f989d546SWilliam Tu 26284e54fe0SWilliam Tu static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi, 26384e54fe0SWilliam Tu int gre_hdr_len) 26484e54fe0SWilliam Tu { 26584e54fe0SWilliam Tu struct net *net = dev_net(skb->dev); 26684e54fe0SWilliam Tu struct metadata_dst *tun_dst = NULL; 2671d7e2ed2SWilliam Tu struct erspan_base_hdr *ershdr; 26884e54fe0SWilliam Tu struct ip_tunnel_net *itn; 26984e54fe0SWilliam Tu struct ip_tunnel *tunnel; 27084e54fe0SWilliam Tu const struct iphdr *iph; 2713df19283SWilliam Tu struct erspan_md2 *md2; 2721d7e2ed2SWilliam Tu int ver; 27384e54fe0SWilliam Tu int len; 27484e54fe0SWilliam Tu 27584e54fe0SWilliam Tu itn = net_generic(net, erspan_net_id); 27684e54fe0SWilliam Tu iph = ip_hdr(skb); 277f989d546SWilliam Tu if (is_erspan_type1(gre_hdr_len)) { 278f989d546SWilliam Tu ver = 0; 279f989d546SWilliam Tu tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, 280f989d546SWilliam Tu tpi->flags | TUNNEL_NO_KEY, 281f989d546SWilliam Tu iph->saddr, iph->daddr, 0); 282f989d546SWilliam Tu } else { 2831d7e2ed2SWilliam Tu ershdr = (struct erspan_base_hdr *)(skb->data + gre_hdr_len); 284c69de58bSWilliam Tu ver = ershdr->ver; 28584e54fe0SWilliam Tu tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, 28684e54fe0SWilliam Tu tpi->flags | TUNNEL_KEY, 28784e54fe0SWilliam Tu iph->saddr, iph->daddr, tpi->key); 288f989d546SWilliam Tu } 28984e54fe0SWilliam Tu 29084e54fe0SWilliam Tu if (tunnel) { 291f989d546SWilliam Tu if (is_erspan_type1(gre_hdr_len)) 292f989d546SWilliam Tu len = gre_hdr_len; 293f989d546SWilliam Tu else 2941d7e2ed2SWilliam Tu len = gre_hdr_len + erspan_hdr_len(ver); 295f989d546SWilliam Tu 2961d7e2ed2SWilliam Tu if (unlikely(!pskb_may_pull(skb, len))) 297ae3e1337SWilliam Tu return PACKET_REJECT; 2981d7e2ed2SWilliam Tu 29984e54fe0SWilliam Tu if (__iptunnel_pull_header(skb, 3001d7e2ed2SWilliam Tu len, 30184e54fe0SWilliam Tu htons(ETH_P_TEB), 30284e54fe0SWilliam Tu false, false) < 0) 30384e54fe0SWilliam Tu goto drop; 30484e54fe0SWilliam Tu 3051a66a836SWilliam Tu if (tunnel->collect_md) { 306492b67e2SLorenzo Bianconi struct erspan_metadata *pkt_md, *md; 3071a66a836SWilliam Tu struct ip_tunnel_info *info; 308492b67e2SLorenzo Bianconi unsigned char *gh; 3091a66a836SWilliam Tu __be64 tun_id; 3101a66a836SWilliam Tu __be16 flags; 3111a66a836SWilliam Tu 3121a66a836SWilliam Tu tpi->flags |= TUNNEL_KEY; 3131a66a836SWilliam Tu flags = tpi->flags; 3141a66a836SWilliam Tu tun_id = key32_to_tunnel_id(tpi->key); 3151a66a836SWilliam Tu 3161a66a836SWilliam Tu tun_dst = ip_tun_rx_dst(skb, flags, 3171a66a836SWilliam Tu tun_id, sizeof(*md)); 3181a66a836SWilliam Tu if (!tun_dst) 3191a66a836SWilliam Tu return PACKET_REJECT; 3201a66a836SWilliam Tu 321492b67e2SLorenzo Bianconi /* skb can be uncloned in __iptunnel_pull_header, so 322492b67e2SLorenzo Bianconi * old pkt_md is no longer valid and we need to reset 323492b67e2SLorenzo Bianconi * it 324492b67e2SLorenzo Bianconi */ 325492b67e2SLorenzo Bianconi gh = skb_network_header(skb) + 326492b67e2SLorenzo Bianconi skb_network_header_len(skb); 327492b67e2SLorenzo Bianconi pkt_md = (struct erspan_metadata *)(gh + gre_hdr_len + 328492b67e2SLorenzo Bianconi sizeof(*ershdr)); 3291a66a836SWilliam Tu md = ip_tunnel_info_opts(&tun_dst->u.tun_info); 330f551c91dSWilliam Tu md->version = ver; 3313df19283SWilliam Tu md2 = &md->u.md2; 3323df19283SWilliam Tu memcpy(md2, pkt_md, ver == 1 ? ERSPAN_V1_MDSIZE : 3333df19283SWilliam Tu ERSPAN_V2_MDSIZE); 334f551c91dSWilliam Tu 3351a66a836SWilliam Tu info = &tun_dst->u.tun_info; 3361a66a836SWilliam Tu info->key.tun_flags |= TUNNEL_ERSPAN_OPT; 3371a66a836SWilliam Tu info->options_len = sizeof(*md); 3381a66a836SWilliam Tu } 3391a66a836SWilliam Tu 34084e54fe0SWilliam Tu skb_reset_mac_header(skb); 34184e54fe0SWilliam Tu ip_tunnel_rcv(tunnel, skb, tpi, tun_dst, log_ecn_error); 34284e54fe0SWilliam Tu return PACKET_RCVD; 34384e54fe0SWilliam Tu } 3445a64506bSHaishuang Yan return PACKET_REJECT; 3455a64506bSHaishuang Yan 34684e54fe0SWilliam Tu drop: 34784e54fe0SWilliam Tu kfree_skb(skb); 34884e54fe0SWilliam Tu return PACKET_RCVD; 34984e54fe0SWilliam Tu } 35084e54fe0SWilliam Tu 351125372faSJiri Benc static int __ipgre_rcv(struct sk_buff *skb, const struct tnl_ptk_info *tpi, 352125372faSJiri Benc struct ip_tunnel_net *itn, int hdr_len, bool raw_proto) 3531da177e4SLinus Torvalds { 3542e15ea39SPravin B Shelar struct metadata_dst *tun_dst = NULL; 355b71d1d42SEric Dumazet const struct iphdr *iph; 3561da177e4SLinus Torvalds struct ip_tunnel *tunnel; 3571da177e4SLinus Torvalds 358eddc9ec5SArnaldo Carvalho de Melo iph = ip_hdr(skb); 359bda7bb46SPravin B Shelar tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, tpi->flags, 360bda7bb46SPravin B Shelar iph->saddr, iph->daddr, tpi->key); 3611da177e4SLinus Torvalds 362d2083287Sstephen hemminger if (tunnel) { 363c0d59da7Swenxu const struct iphdr *tnl_params; 364c0d59da7Swenxu 365125372faSJiri Benc if (__iptunnel_pull_header(skb, hdr_len, tpi->proto, 366125372faSJiri Benc raw_proto, false) < 0) 367244a797bSJiri Benc goto drop; 368244a797bSJiri Benc 369aab1e898SGuillaume Nault /* Special case for ipgre_header_parse(), which expects the 370aab1e898SGuillaume Nault * mac_header to point to the outer IP header. 371aab1e898SGuillaume Nault */ 372aab1e898SGuillaume Nault if (tunnel->dev->header_ops == &ipgre_header_ops) 3730e3da5bbSTimo Teräs skb_pop_mac_header(skb); 374e271c7b4SJiri Benc else 375e271c7b4SJiri Benc skb_reset_mac_header(skb); 376c0d59da7Swenxu 377c0d59da7Swenxu tnl_params = &tunnel->parms.iph; 378c0d59da7Swenxu if (tunnel->collect_md || tnl_params->daddr == 0) { 379c29a70d2SPravin B Shelar __be16 flags; 380c29a70d2SPravin B Shelar __be64 tun_id; 3812e15ea39SPravin B Shelar 382c29a70d2SPravin B Shelar flags = tpi->flags & (TUNNEL_CSUM | TUNNEL_KEY); 383d817f432SAmir Vadai tun_id = key32_to_tunnel_id(tpi->key); 384c29a70d2SPravin B Shelar tun_dst = ip_tun_rx_dst(skb, flags, tun_id, 0); 3852e15ea39SPravin B Shelar if (!tun_dst) 3862e15ea39SPravin B Shelar return PACKET_REJECT; 3872e15ea39SPravin B Shelar } 3882e15ea39SPravin B Shelar 3892e15ea39SPravin B Shelar ip_tunnel_rcv(tunnel, skb, tpi, tun_dst, log_ecn_error); 390bda7bb46SPravin B Shelar return PACKET_RCVD; 3911da177e4SLinus Torvalds } 392125372faSJiri Benc return PACKET_NEXT; 393244a797bSJiri Benc 394244a797bSJiri Benc drop: 395244a797bSJiri Benc kfree_skb(skb); 396244a797bSJiri Benc return PACKET_RCVD; 3971da177e4SLinus Torvalds } 3981da177e4SLinus Torvalds 399125372faSJiri Benc static int ipgre_rcv(struct sk_buff *skb, const struct tnl_ptk_info *tpi, 400125372faSJiri Benc int hdr_len) 401125372faSJiri Benc { 402125372faSJiri Benc struct net *net = dev_net(skb->dev); 403125372faSJiri Benc struct ip_tunnel_net *itn; 404125372faSJiri Benc int res; 405125372faSJiri Benc 406125372faSJiri Benc if (tpi->proto == htons(ETH_P_TEB)) 407125372faSJiri Benc itn = net_generic(net, gre_tap_net_id); 408125372faSJiri Benc else 409125372faSJiri Benc itn = net_generic(net, ipgre_net_id); 410125372faSJiri Benc 411125372faSJiri Benc res = __ipgre_rcv(skb, tpi, itn, hdr_len, false); 412125372faSJiri Benc if (res == PACKET_NEXT && tpi->proto == htons(ETH_P_TEB)) { 413125372faSJiri Benc /* ipgre tunnels in collect metadata mode should receive 414125372faSJiri Benc * also ETH_P_TEB traffic. 415125372faSJiri Benc */ 416125372faSJiri Benc itn = net_generic(net, ipgre_net_id); 417125372faSJiri Benc res = __ipgre_rcv(skb, tpi, itn, hdr_len, true); 418125372faSJiri Benc } 419125372faSJiri Benc return res; 420125372faSJiri Benc } 421125372faSJiri Benc 4229f57c67cSPravin B Shelar static int gre_rcv(struct sk_buff *skb) 4239f57c67cSPravin B Shelar { 4249f57c67cSPravin B Shelar struct tnl_ptk_info tpi; 4259f57c67cSPravin B Shelar bool csum_err = false; 42695f5c64cSTom Herbert int hdr_len; 4279f57c67cSPravin B Shelar 4289f57c67cSPravin B Shelar #ifdef CONFIG_NET_IPGRE_BROADCAST 4299f57c67cSPravin B Shelar if (ipv4_is_multicast(ip_hdr(skb)->daddr)) { 4309f57c67cSPravin B Shelar /* Looped back packet, drop it! */ 4319f57c67cSPravin B Shelar if (rt_is_output_route(skb_rtable(skb))) 4329f57c67cSPravin B Shelar goto drop; 4339f57c67cSPravin B Shelar } 4349f57c67cSPravin B Shelar #endif 4359f57c67cSPravin B Shelar 436e582615aSEric Dumazet hdr_len = gre_parse_header(skb, &tpi, &csum_err, htons(ETH_P_IP), 0); 437f132ae7cSJiri Benc if (hdr_len < 0) 43895f5c64cSTom Herbert goto drop; 43995f5c64cSTom Herbert 440f551c91dSWilliam Tu if (unlikely(tpi.proto == htons(ETH_P_ERSPAN) || 441f551c91dSWilliam Tu tpi.proto == htons(ETH_P_ERSPAN2))) { 44284e54fe0SWilliam Tu if (erspan_rcv(skb, &tpi, hdr_len) == PACKET_RCVD) 44384e54fe0SWilliam Tu return 0; 444dd8d5b8cSHaishuang Yan goto out; 44584e54fe0SWilliam Tu } 44684e54fe0SWilliam Tu 447244a797bSJiri Benc if (ipgre_rcv(skb, &tpi, hdr_len) == PACKET_RCVD) 4489f57c67cSPravin B Shelar return 0; 4499f57c67cSPravin B Shelar 450dd8d5b8cSHaishuang Yan out: 4519f57c67cSPravin B Shelar icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); 4529f57c67cSPravin B Shelar drop: 4539f57c67cSPravin B Shelar kfree_skb(skb); 4549f57c67cSPravin B Shelar return 0; 4559f57c67cSPravin B Shelar } 4569f57c67cSPravin B Shelar 457c5441932SPravin B Shelar static void __gre_xmit(struct sk_buff *skb, struct net_device *dev, 458c5441932SPravin B Shelar const struct iphdr *tnl_params, 459c5441932SPravin B Shelar __be16 proto) 460c5441932SPravin B Shelar { 461c5441932SPravin B Shelar struct ip_tunnel *tunnel = netdev_priv(dev); 462ff827bebSPeilin Ye __be16 flags = tunnel->parms.o_flags; 463cef401deSEric Dumazet 464c5441932SPravin B Shelar /* Push GRE header. */ 465182a352dSTom Herbert gre_build_header(skb, tunnel->tun_hlen, 466ff827bebSPeilin Ye flags, proto, tunnel->parms.o_key, 46731c417c9SPeilin Ye (flags & TUNNEL_SEQ) ? htonl(atomic_fetch_inc(&tunnel->o_seqno)) : 0); 4681da177e4SLinus Torvalds 469bf3d6a8fSNicolas Dichtel ip_tunnel_xmit(skb, dev, tnl_params, tnl_params->protocol); 4701da177e4SLinus Torvalds } 4711da177e4SLinus Torvalds 472aed069dfSAlexander Duyck static int gre_handle_offloads(struct sk_buff *skb, bool csum) 473b2acd1dcSPravin B Shelar { 4746fa79666SEdward Cree return iptunnel_handle_offloads(skb, csum ? SKB_GSO_GRE_CSUM : SKB_GSO_GRE); 475b2acd1dcSPravin B Shelar } 476b2acd1dcSPravin B Shelar 477862a03c3SWilliam Tu static void gre_fb_xmit(struct sk_buff *skb, struct net_device *dev, 478862a03c3SWilliam Tu __be16 proto) 479862a03c3SWilliam Tu { 48077a5196aSWilliam Tu struct ip_tunnel *tunnel = netdev_priv(dev); 481862a03c3SWilliam Tu struct ip_tunnel_info *tun_info; 482862a03c3SWilliam Tu const struct ip_tunnel_key *key; 483862a03c3SWilliam Tu int tunnel_hlen; 484962924faSwenxu __be16 flags; 485862a03c3SWilliam Tu 486862a03c3SWilliam Tu tun_info = skb_tunnel_info(skb); 487862a03c3SWilliam Tu if (unlikely(!tun_info || !(tun_info->mode & IP_TUNNEL_INFO_TX) || 488862a03c3SWilliam Tu ip_tunnel_info_af(tun_info) != AF_INET)) 489862a03c3SWilliam Tu goto err_free_skb; 490862a03c3SWilliam Tu 491862a03c3SWilliam Tu key = &tun_info->key; 492862a03c3SWilliam Tu tunnel_hlen = gre_calc_hlen(key->tun_flags); 493862a03c3SWilliam Tu 494962924faSwenxu if (skb_cow_head(skb, dev->needed_headroom)) 495962924faSwenxu goto err_free_skb; 4962e15ea39SPravin B Shelar 4972e15ea39SPravin B Shelar /* Push Tunnel header. */ 498aed069dfSAlexander Duyck if (gre_handle_offloads(skb, !!(tun_info->key.tun_flags & TUNNEL_CSUM))) 499962924faSwenxu goto err_free_skb; 5002e15ea39SPravin B Shelar 50177a5196aSWilliam Tu flags = tun_info->key.tun_flags & 50277a5196aSWilliam Tu (TUNNEL_CSUM | TUNNEL_KEY | TUNNEL_SEQ); 503cba65321SDavid S. Miller gre_build_header(skb, tunnel_hlen, flags, proto, 50477a5196aSWilliam Tu tunnel_id_to_key32(tun_info->key.tun_id), 50531c417c9SPeilin Ye (flags & TUNNEL_SEQ) ? htonl(atomic_fetch_inc(&tunnel->o_seqno)) : 0); 5062e15ea39SPravin B Shelar 507962924faSwenxu ip_md_tunnel_xmit(skb, dev, IPPROTO_GRE, tunnel_hlen); 508039f5062SPravin B Shelar 5092e15ea39SPravin B Shelar return; 5102e15ea39SPravin B Shelar 5112e15ea39SPravin B Shelar err_free_skb: 5122e15ea39SPravin B Shelar kfree_skb(skb); 513c4794d22SEric Dumazet DEV_STATS_INC(dev, tx_dropped); 5142e15ea39SPravin B Shelar } 5152e15ea39SPravin B Shelar 51620704bd1SXin Long static void erspan_fb_xmit(struct sk_buff *skb, struct net_device *dev) 5171a66a836SWilliam Tu { 5181a66a836SWilliam Tu struct ip_tunnel *tunnel = netdev_priv(dev); 5191a66a836SWilliam Tu struct ip_tunnel_info *tun_info; 5201a66a836SWilliam Tu const struct ip_tunnel_key *key; 5211a66a836SWilliam Tu struct erspan_metadata *md; 5221a66a836SWilliam Tu bool truncate = false; 523962924faSwenxu __be16 proto; 5241a66a836SWilliam Tu int tunnel_hlen; 525f551c91dSWilliam Tu int version; 5261baf5ebfSWilliam Tu int nhoff; 5271a66a836SWilliam Tu 5281a66a836SWilliam Tu tun_info = skb_tunnel_info(skb); 5291a66a836SWilliam Tu if (unlikely(!tun_info || !(tun_info->mode & IP_TUNNEL_INFO_TX) || 5301a66a836SWilliam Tu ip_tunnel_info_af(tun_info) != AF_INET)) 5311a66a836SWilliam Tu goto err_free_skb; 5321a66a836SWilliam Tu 5331a66a836SWilliam Tu key = &tun_info->key; 534256c87c1SPieter Jansen van Vuuren if (!(tun_info->key.tun_flags & TUNNEL_ERSPAN_OPT)) 535962924faSwenxu goto err_free_skb; 5362eb8d6d2SXin Long if (tun_info->options_len < sizeof(*md)) 537962924faSwenxu goto err_free_skb; 5382eb8d6d2SXin Long md = ip_tunnel_info_opts(tun_info); 5391a66a836SWilliam Tu 5401a66a836SWilliam Tu /* ERSPAN has fixed 8 byte GRE header */ 541f551c91dSWilliam Tu version = md->version; 542f551c91dSWilliam Tu tunnel_hlen = 8 + erspan_hdr_len(version); 5431a66a836SWilliam Tu 544962924faSwenxu if (skb_cow_head(skb, dev->needed_headroom)) 545962924faSwenxu goto err_free_skb; 5461a66a836SWilliam Tu 5471a66a836SWilliam Tu if (gre_handle_offloads(skb, false)) 548962924faSwenxu goto err_free_skb; 5491a66a836SWilliam Tu 550f192970dSWilliam Tu if (skb->len > dev->mtu + dev->hard_header_len) { 55102d84f3eSYuanjun Gong if (pskb_trim(skb, dev->mtu + dev->hard_header_len)) 55202d84f3eSYuanjun Gong goto err_free_skb; 5531a66a836SWilliam Tu truncate = true; 5541a66a836SWilliam Tu } 5551a66a836SWilliam Tu 5568e50ed77SEric Dumazet nhoff = skb_network_offset(skb); 5571baf5ebfSWilliam Tu if (skb->protocol == htons(ETH_P_IP) && 5581baf5ebfSWilliam Tu (ntohs(ip_hdr(skb)->tot_len) > skb->len - nhoff)) 5591baf5ebfSWilliam Tu truncate = true; 5601baf5ebfSWilliam Tu 561301bd140SEric Dumazet if (skb->protocol == htons(ETH_P_IPV6)) { 562301bd140SEric Dumazet int thoff; 563301bd140SEric Dumazet 564301bd140SEric Dumazet if (skb_transport_header_was_set(skb)) 5658e50ed77SEric Dumazet thoff = skb_transport_offset(skb); 566301bd140SEric Dumazet else 567301bd140SEric Dumazet thoff = nhoff + sizeof(struct ipv6hdr); 568301bd140SEric Dumazet if (ntohs(ipv6_hdr(skb)->payload_len) > skb->len - thoff) 569d5db21a3SWilliam Tu truncate = true; 570301bd140SEric Dumazet } 571d5db21a3SWilliam Tu 572f551c91dSWilliam Tu if (version == 1) { 573c69de58bSWilliam Tu erspan_build_header(skb, ntohl(tunnel_id_to_key32(key->tun_id)), 5741d7e2ed2SWilliam Tu ntohl(md->u.index), truncate, true); 57520704bd1SXin Long proto = htons(ETH_P_ERSPAN); 576f551c91dSWilliam Tu } else if (version == 2) { 577c69de58bSWilliam Tu erspan_build_header_v2(skb, 578c69de58bSWilliam Tu ntohl(tunnel_id_to_key32(key->tun_id)), 579c69de58bSWilliam Tu md->u.md2.dir, 580c69de58bSWilliam Tu get_hwid(&md->u.md2), 581c69de58bSWilliam Tu truncate, true); 58220704bd1SXin Long proto = htons(ETH_P_ERSPAN2); 583f551c91dSWilliam Tu } else { 584962924faSwenxu goto err_free_skb; 585f551c91dSWilliam Tu } 5861a66a836SWilliam Tu 5871a66a836SWilliam Tu gre_build_header(skb, 8, TUNNEL_SEQ, 58831c417c9SPeilin Ye proto, 0, htonl(atomic_fetch_inc(&tunnel->o_seqno))); 5891a66a836SWilliam Tu 590962924faSwenxu ip_md_tunnel_xmit(skb, dev, IPPROTO_GRE, tunnel_hlen); 5911a66a836SWilliam Tu 5921a66a836SWilliam Tu return; 5931a66a836SWilliam Tu 5941a66a836SWilliam Tu err_free_skb: 5951a66a836SWilliam Tu kfree_skb(skb); 596c4794d22SEric Dumazet DEV_STATS_INC(dev, tx_dropped); 5971a66a836SWilliam Tu } 5981a66a836SWilliam Tu 599fc4099f1SPravin B Shelar static int gre_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb) 600fc4099f1SPravin B Shelar { 601fc4099f1SPravin B Shelar struct ip_tunnel_info *info = skb_tunnel_info(skb); 602962924faSwenxu const struct ip_tunnel_key *key; 603fc4099f1SPravin B Shelar struct rtable *rt; 604fc4099f1SPravin B Shelar struct flowi4 fl4; 605fc4099f1SPravin B Shelar 606fc4099f1SPravin B Shelar if (ip_tunnel_info_af(info) != AF_INET) 607fc4099f1SPravin B Shelar return -EINVAL; 608fc4099f1SPravin B Shelar 609962924faSwenxu key = &info->key; 610962924faSwenxu ip_tunnel_init_flow(&fl4, IPPROTO_GRE, key->u.ipv4.dst, key->u.ipv4.src, 611f7716b31SGuillaume Nault tunnel_id_to_key32(key->tun_id), 612db53cd3dSDavid Ahern key->tos & ~INET_ECN_MASK, dev_net(dev), 0, 6137ec9fce4SEyal Birger skb->mark, skb_get_hash(skb), key->flow_flags); 614962924faSwenxu rt = ip_route_output_key(dev_net(dev), &fl4); 615fc4099f1SPravin B Shelar if (IS_ERR(rt)) 616fc4099f1SPravin B Shelar return PTR_ERR(rt); 617fc4099f1SPravin B Shelar 618fc4099f1SPravin B Shelar ip_rt_put(rt); 619fc4099f1SPravin B Shelar info->key.u.ipv4.src = fl4.saddr; 620fc4099f1SPravin B Shelar return 0; 621fc4099f1SPravin B Shelar } 622fc4099f1SPravin B Shelar 623c5441932SPravin B Shelar static netdev_tx_t ipgre_xmit(struct sk_buff *skb, 624c5441932SPravin B Shelar struct net_device *dev) 625ee34c1ebSMichal Schmidt { 626c5441932SPravin B Shelar struct ip_tunnel *tunnel = netdev_priv(dev); 627c5441932SPravin B Shelar const struct iphdr *tnl_params; 628ee34c1ebSMichal Schmidt 629cb9f1b78SWillem de Bruijn if (!pskb_inet_may_pull(skb)) 630cb9f1b78SWillem de Bruijn goto free_skb; 631cb9f1b78SWillem de Bruijn 6322e15ea39SPravin B Shelar if (tunnel->collect_md) { 6332090714eSJiri Benc gre_fb_xmit(skb, dev, skb->protocol); 6342e15ea39SPravin B Shelar return NETDEV_TX_OK; 6352e15ea39SPravin B Shelar } 6362e15ea39SPravin B Shelar 637c5441932SPravin B Shelar if (dev->header_ops) { 63880d875cfSShigeru Yoshida int pull_len = tunnel->hlen + sizeof(struct iphdr); 63980d875cfSShigeru Yoshida 640fdafed45SCong Wang if (skb_cow_head(skb, 0)) 641c5441932SPravin B Shelar goto free_skb; 642ee34c1ebSMichal Schmidt 643c5441932SPravin B Shelar tnl_params = (const struct iphdr *)skb->data; 644cbb1e85fSDavid S. Miller 64580d875cfSShigeru Yoshida if (!pskb_network_may_pull(skb, pull_len)) 64680d875cfSShigeru Yoshida goto free_skb; 64780d875cfSShigeru Yoshida 64880d875cfSShigeru Yoshida /* ip_tunnel_xmit() needs skb->data pointing to gre header. */ 64980d875cfSShigeru Yoshida skb_pull(skb, pull_len); 6508a0033a9STimo Teräs skb_reset_mac_header(skb); 6518d21e996SWillem de Bruijn 6528d21e996SWillem de Bruijn if (skb->ip_summed == CHECKSUM_PARTIAL && 6538d21e996SWillem de Bruijn skb_checksum_start(skb) < skb->data) 6548d21e996SWillem de Bruijn goto free_skb; 655c5441932SPravin B Shelar } else { 656c5441932SPravin B Shelar if (skb_cow_head(skb, dev->needed_headroom)) 657c5441932SPravin B Shelar goto free_skb; 658c5441932SPravin B Shelar 659c5441932SPravin B Shelar tnl_params = &tunnel->parms.iph; 660ee34c1ebSMichal Schmidt } 661e1a80002SHerbert Xu 662aed069dfSAlexander Duyck if (gre_handle_offloads(skb, !!(tunnel->parms.o_flags & TUNNEL_CSUM))) 663aed069dfSAlexander Duyck goto free_skb; 6648a0033a9STimo Teräs 665c5441932SPravin B Shelar __gre_xmit(skb, dev, tnl_params, skb->protocol); 666c5441932SPravin B Shelar return NETDEV_TX_OK; 667c5441932SPravin B Shelar 668c5441932SPravin B Shelar free_skb: 6693acfa1e7SEric Dumazet kfree_skb(skb); 670c4794d22SEric Dumazet DEV_STATS_INC(dev, tx_dropped); 671c5441932SPravin B Shelar return NETDEV_TX_OK; 672ee34c1ebSMichal Schmidt } 673ee34c1ebSMichal Schmidt 67484e54fe0SWilliam Tu static netdev_tx_t erspan_xmit(struct sk_buff *skb, 67584e54fe0SWilliam Tu struct net_device *dev) 67684e54fe0SWilliam Tu { 67784e54fe0SWilliam Tu struct ip_tunnel *tunnel = netdev_priv(dev); 67884e54fe0SWilliam Tu bool truncate = false; 67920704bd1SXin Long __be16 proto; 68084e54fe0SWilliam Tu 681cb9f1b78SWillem de Bruijn if (!pskb_inet_may_pull(skb)) 682cb9f1b78SWillem de Bruijn goto free_skb; 683cb9f1b78SWillem de Bruijn 6841a66a836SWilliam Tu if (tunnel->collect_md) { 68520704bd1SXin Long erspan_fb_xmit(skb, dev); 6861a66a836SWilliam Tu return NETDEV_TX_OK; 6871a66a836SWilliam Tu } 6881a66a836SWilliam Tu 68984e54fe0SWilliam Tu if (gre_handle_offloads(skb, false)) 69084e54fe0SWilliam Tu goto free_skb; 69184e54fe0SWilliam Tu 69284e54fe0SWilliam Tu if (skb_cow_head(skb, dev->needed_headroom)) 69384e54fe0SWilliam Tu goto free_skb; 69484e54fe0SWilliam Tu 695f192970dSWilliam Tu if (skb->len > dev->mtu + dev->hard_header_len) { 696aa7cb378SYuanjun Gong if (pskb_trim(skb, dev->mtu + dev->hard_header_len)) 697aa7cb378SYuanjun Gong goto free_skb; 69884e54fe0SWilliam Tu truncate = true; 69984e54fe0SWilliam Tu } 70084e54fe0SWilliam Tu 70184e54fe0SWilliam Tu /* Push ERSPAN header */ 702f989d546SWilliam Tu if (tunnel->erspan_ver == 0) { 703f989d546SWilliam Tu proto = htons(ETH_P_ERSPAN); 704f989d546SWilliam Tu tunnel->parms.o_flags &= ~TUNNEL_SEQ; 705f989d546SWilliam Tu } else if (tunnel->erspan_ver == 1) { 706c69de58bSWilliam Tu erspan_build_header(skb, ntohl(tunnel->parms.o_key), 707c69de58bSWilliam Tu tunnel->index, 708a3222dc9SWilliam Tu truncate, true); 70920704bd1SXin Long proto = htons(ETH_P_ERSPAN); 71020704bd1SXin Long } else if (tunnel->erspan_ver == 2) { 711c69de58bSWilliam Tu erspan_build_header_v2(skb, ntohl(tunnel->parms.o_key), 712f551c91dSWilliam Tu tunnel->dir, tunnel->hwid, 713f551c91dSWilliam Tu truncate, true); 71420704bd1SXin Long proto = htons(ETH_P_ERSPAN2); 71520704bd1SXin Long } else { 71602f99df1SWilliam Tu goto free_skb; 71720704bd1SXin Long } 718f551c91dSWilliam Tu 71984e54fe0SWilliam Tu tunnel->parms.o_flags &= ~TUNNEL_KEY; 72020704bd1SXin Long __gre_xmit(skb, dev, &tunnel->parms.iph, proto); 72184e54fe0SWilliam Tu return NETDEV_TX_OK; 72284e54fe0SWilliam Tu 72384e54fe0SWilliam Tu free_skb: 72484e54fe0SWilliam Tu kfree_skb(skb); 725c4794d22SEric Dumazet DEV_STATS_INC(dev, tx_dropped); 72684e54fe0SWilliam Tu return NETDEV_TX_OK; 72784e54fe0SWilliam Tu } 72884e54fe0SWilliam Tu 729c5441932SPravin B Shelar static netdev_tx_t gre_tap_xmit(struct sk_buff *skb, 730c5441932SPravin B Shelar struct net_device *dev) 731c5441932SPravin B Shelar { 732c5441932SPravin B Shelar struct ip_tunnel *tunnel = netdev_priv(dev); 733ee34c1ebSMichal Schmidt 734cb9f1b78SWillem de Bruijn if (!pskb_inet_may_pull(skb)) 735cb9f1b78SWillem de Bruijn goto free_skb; 736cb9f1b78SWillem de Bruijn 7372e15ea39SPravin B Shelar if (tunnel->collect_md) { 7382090714eSJiri Benc gre_fb_xmit(skb, dev, htons(ETH_P_TEB)); 7392e15ea39SPravin B Shelar return NETDEV_TX_OK; 7402e15ea39SPravin B Shelar } 7412e15ea39SPravin B Shelar 742aed069dfSAlexander Duyck if (gre_handle_offloads(skb, !!(tunnel->parms.o_flags & TUNNEL_CSUM))) 743aed069dfSAlexander Duyck goto free_skb; 744ee34c1ebSMichal Schmidt 745c5441932SPravin B Shelar if (skb_cow_head(skb, dev->needed_headroom)) 746c5441932SPravin B Shelar goto free_skb; 74742aa9162SHerbert Xu 748c5441932SPravin B Shelar __gre_xmit(skb, dev, &tunnel->parms.iph, htons(ETH_P_TEB)); 749c5441932SPravin B Shelar return NETDEV_TX_OK; 750c5441932SPravin B Shelar 751c5441932SPravin B Shelar free_skb: 7523acfa1e7SEric Dumazet kfree_skb(skb); 753c4794d22SEric Dumazet DEV_STATS_INC(dev, tx_dropped); 754c5441932SPravin B Shelar return NETDEV_TX_OK; 75568c33163SPravin B Shelar } 756ee34c1ebSMichal Schmidt 757dd9d598cSXin Long static void ipgre_link_update(struct net_device *dev, bool set_mtu) 758dd9d598cSXin Long { 759dd9d598cSXin Long struct ip_tunnel *tunnel = netdev_priv(dev); 760020e8f60SPeilin Ye __be16 flags; 761dd9d598cSXin Long int len; 762dd9d598cSXin Long 763dd9d598cSXin Long len = tunnel->tun_hlen; 764dd9d598cSXin Long tunnel->tun_hlen = gre_calc_hlen(tunnel->parms.o_flags); 765dd9d598cSXin Long len = tunnel->tun_hlen - len; 766dd9d598cSXin Long tunnel->hlen = tunnel->hlen + len; 767dd9d598cSXin Long 768fdafed45SCong Wang if (dev->header_ops) 769fdafed45SCong Wang dev->hard_header_len += len; 770fdafed45SCong Wang else 771fdafed45SCong Wang dev->needed_headroom += len; 772fdafed45SCong Wang 773dd9d598cSXin Long if (set_mtu) 774dd9d598cSXin Long dev->mtu = max_t(int, dev->mtu - len, 68); 775dd9d598cSXin Long 776020e8f60SPeilin Ye flags = tunnel->parms.o_flags; 777020e8f60SPeilin Ye 778020e8f60SPeilin Ye if (flags & TUNNEL_SEQ || 779020e8f60SPeilin Ye (flags & TUNNEL_CSUM && tunnel->encap.type != TUNNEL_ENCAP_NONE)) { 7801cc5954fSSabrina Dubroca dev->features &= ~NETIF_F_GSO_SOFTWARE; 7811cc5954fSSabrina Dubroca dev->hw_features &= ~NETIF_F_GSO_SOFTWARE; 7821cc5954fSSabrina Dubroca } else { 783020e8f60SPeilin Ye dev->features |= NETIF_F_GSO_SOFTWARE; 784020e8f60SPeilin Ye dev->hw_features |= NETIF_F_GSO_SOFTWARE; 785dd9d598cSXin Long } 786dd9d598cSXin Long } 787dd9d598cSXin Long 788607259a6SChristoph Hellwig static int ipgre_tunnel_ctl(struct net_device *dev, struct ip_tunnel_parm *p, 789607259a6SChristoph Hellwig int cmd) 7901da177e4SLinus Torvalds { 791a0efab67SXin Long int err; 7921da177e4SLinus Torvalds 7936c734fb8SCong Wang if (cmd == SIOCADDTUNNEL || cmd == SIOCCHGTUNNEL) { 794607259a6SChristoph Hellwig if (p->iph.version != 4 || p->iph.protocol != IPPROTO_GRE || 795607259a6SChristoph Hellwig p->iph.ihl != 5 || (p->iph.frag_off & htons(~IP_DF)) || 796607259a6SChristoph Hellwig ((p->i_flags | p->o_flags) & (GRE_VERSION | GRE_ROUTING))) 7971da177e4SLinus Torvalds return -EINVAL; 798c5441932SPravin B Shelar } 799a0efab67SXin Long 800607259a6SChristoph Hellwig p->i_flags = gre_flags_to_tnl_flags(p->i_flags); 801607259a6SChristoph Hellwig p->o_flags = gre_flags_to_tnl_flags(p->o_flags); 802c5441932SPravin B Shelar 803607259a6SChristoph Hellwig err = ip_tunnel_ctl(dev, p, cmd); 804c5441932SPravin B Shelar if (err) 805c5441932SPravin B Shelar return err; 806c5441932SPravin B Shelar 807a0efab67SXin Long if (cmd == SIOCCHGTUNNEL) { 808a0efab67SXin Long struct ip_tunnel *t = netdev_priv(dev); 809a0efab67SXin Long 810607259a6SChristoph Hellwig t->parms.i_flags = p->i_flags; 811607259a6SChristoph Hellwig t->parms.o_flags = p->o_flags; 812a0efab67SXin Long 813a0efab67SXin Long if (strcmp(dev->rtnl_link_ops->kind, "erspan")) 814a0efab67SXin Long ipgre_link_update(dev, true); 815a0efab67SXin Long } 816a0efab67SXin Long 817607259a6SChristoph Hellwig p->i_flags = gre_tnl_flags_to_gre_flags(p->i_flags); 818607259a6SChristoph Hellwig p->o_flags = gre_tnl_flags_to_gre_flags(p->o_flags); 8191da177e4SLinus Torvalds return 0; 8201da177e4SLinus Torvalds } 8211da177e4SLinus Torvalds 8221da177e4SLinus Torvalds /* Nice toy. Unfortunately, useless in real life :-) 8231da177e4SLinus Torvalds It allows to construct virtual multiprotocol broadcast "LAN" 8241da177e4SLinus Torvalds over the Internet, provided multicast routing is tuned. 8251da177e4SLinus Torvalds 8261da177e4SLinus Torvalds 8271da177e4SLinus Torvalds I have no idea was this bicycle invented before me, 8281da177e4SLinus Torvalds so that I had to set ARPHRD_IPGRE to a random value. 8291da177e4SLinus Torvalds I have an impression, that Cisco could make something similar, 8301da177e4SLinus Torvalds but this feature is apparently missing in IOS<=11.2(8). 8311da177e4SLinus Torvalds 8321da177e4SLinus Torvalds I set up 10.66.66/24 and fec0:6666:6666::0/96 as virtual networks 8331da177e4SLinus Torvalds with broadcast 224.66.66.66. If you have access to mbone, play with me :-) 8341da177e4SLinus Torvalds 8351da177e4SLinus Torvalds ping -t 255 224.66.66.66 8361da177e4SLinus Torvalds 8371da177e4SLinus Torvalds If nobody answers, mbone does not work. 8381da177e4SLinus Torvalds 8391da177e4SLinus Torvalds ip tunnel add Universe mode gre remote 224.66.66.66 local <Your_real_addr> ttl 255 8401da177e4SLinus Torvalds ip addr add 10.66.66.<somewhat>/24 dev Universe 8411da177e4SLinus Torvalds ifconfig Universe up 8421da177e4SLinus Torvalds ifconfig Universe add fe80::<Your_real_addr>/10 8431da177e4SLinus Torvalds ifconfig Universe add fec0:6666:6666::<Your_real_addr>/96 8441da177e4SLinus Torvalds ftp 10.66.66.66 8451da177e4SLinus Torvalds ... 8461da177e4SLinus Torvalds ftp fec0:6666:6666::193.233.7.65 8471da177e4SLinus Torvalds ... 8481da177e4SLinus Torvalds */ 8493b04dddeSStephen Hemminger static int ipgre_header(struct sk_buff *skb, struct net_device *dev, 8503b04dddeSStephen Hemminger unsigned short type, 8511507850bSEric Dumazet const void *daddr, const void *saddr, unsigned int len) 8521da177e4SLinus Torvalds { 8532941a486SPatrick McHardy struct ip_tunnel *t = netdev_priv(dev); 854c5441932SPravin B Shelar struct iphdr *iph; 855c5441932SPravin B Shelar struct gre_base_hdr *greh; 856c5441932SPravin B Shelar 857d58ff351SJohannes Berg iph = skb_push(skb, t->hlen + sizeof(*iph)); 858c5441932SPravin B Shelar greh = (struct gre_base_hdr *)(iph+1); 85995f5c64cSTom Herbert greh->flags = gre_tnl_flags_to_gre_flags(t->parms.o_flags); 860c5441932SPravin B Shelar greh->protocol = htons(type); 8611da177e4SLinus Torvalds 8621da177e4SLinus Torvalds memcpy(iph, &t->parms.iph, sizeof(struct iphdr)); 8631da177e4SLinus Torvalds 864c5441932SPravin B Shelar /* Set the source hardware address. */ 8651da177e4SLinus Torvalds if (saddr) 8661da177e4SLinus Torvalds memcpy(&iph->saddr, saddr, 4); 8676d55cb91STimo Teräs if (daddr) 8681da177e4SLinus Torvalds memcpy(&iph->daddr, daddr, 4); 8696d55cb91STimo Teräs if (iph->daddr) 87077a482bdSTimo Teräs return t->hlen + sizeof(*iph); 8711da177e4SLinus Torvalds 872c5441932SPravin B Shelar return -(t->hlen + sizeof(*iph)); 8731da177e4SLinus Torvalds } 8741da177e4SLinus Torvalds 8756a5f44d7STimo Teras static int ipgre_header_parse(const struct sk_buff *skb, unsigned char *haddr) 8766a5f44d7STimo Teras { 877b71d1d42SEric Dumazet const struct iphdr *iph = (const struct iphdr *) skb_mac_header(skb); 8786a5f44d7STimo Teras memcpy(haddr, &iph->saddr, 4); 8796a5f44d7STimo Teras return 4; 8806a5f44d7STimo Teras } 8816a5f44d7STimo Teras 8823b04dddeSStephen Hemminger static const struct header_ops ipgre_header_ops = { 8833b04dddeSStephen Hemminger .create = ipgre_header, 8846a5f44d7STimo Teras .parse = ipgre_header_parse, 8853b04dddeSStephen Hemminger }; 8863b04dddeSStephen Hemminger 8876a5f44d7STimo Teras #ifdef CONFIG_NET_IPGRE_BROADCAST 8881da177e4SLinus Torvalds static int ipgre_open(struct net_device *dev) 8891da177e4SLinus Torvalds { 8902941a486SPatrick McHardy struct ip_tunnel *t = netdev_priv(dev); 8911da177e4SLinus Torvalds 892f97c1e0cSJoe Perches if (ipv4_is_multicast(t->parms.iph.daddr)) { 893cbb1e85fSDavid S. Miller struct flowi4 fl4; 894cbb1e85fSDavid S. Miller struct rtable *rt; 895cbb1e85fSDavid S. Miller 896b57708adSNicolas Dichtel rt = ip_route_output_gre(t->net, &fl4, 89778fbfd8aSDavid S. Miller t->parms.iph.daddr, 89878fbfd8aSDavid S. Miller t->parms.iph.saddr, 89978fbfd8aSDavid S. Miller t->parms.o_key, 90078fbfd8aSDavid S. Miller RT_TOS(t->parms.iph.tos), 90178fbfd8aSDavid S. Miller t->parms.link); 902b23dd4feSDavid S. Miller if (IS_ERR(rt)) 9031da177e4SLinus Torvalds return -EADDRNOTAVAIL; 904d8d1f30bSChangli Gao dev = rt->dst.dev; 9051da177e4SLinus Torvalds ip_rt_put(rt); 90651456b29SIan Morris if (!__in_dev_get_rtnl(dev)) 9071da177e4SLinus Torvalds return -EADDRNOTAVAIL; 9081da177e4SLinus Torvalds t->mlink = dev->ifindex; 909e5ed6399SHerbert Xu ip_mc_inc_group(__in_dev_get_rtnl(dev), t->parms.iph.daddr); 9101da177e4SLinus Torvalds } 9111da177e4SLinus Torvalds return 0; 9121da177e4SLinus Torvalds } 9131da177e4SLinus Torvalds 9141da177e4SLinus Torvalds static int ipgre_close(struct net_device *dev) 9151da177e4SLinus Torvalds { 9162941a486SPatrick McHardy struct ip_tunnel *t = netdev_priv(dev); 917b8c26a33SStephen Hemminger 918f97c1e0cSJoe Perches if (ipv4_is_multicast(t->parms.iph.daddr) && t->mlink) { 9197fee0ca2SDenis V. Lunev struct in_device *in_dev; 920b57708adSNicolas Dichtel in_dev = inetdev_by_index(t->net, t->mlink); 9218723e1b4SEric Dumazet if (in_dev) 9221da177e4SLinus Torvalds ip_mc_dec_group(in_dev, t->parms.iph.daddr); 9231da177e4SLinus Torvalds } 9241da177e4SLinus Torvalds return 0; 9251da177e4SLinus Torvalds } 9261da177e4SLinus Torvalds #endif 9271da177e4SLinus Torvalds 928b8c26a33SStephen Hemminger static const struct net_device_ops ipgre_netdev_ops = { 929b8c26a33SStephen Hemminger .ndo_init = ipgre_tunnel_init, 930c5441932SPravin B Shelar .ndo_uninit = ip_tunnel_uninit, 931b8c26a33SStephen Hemminger #ifdef CONFIG_NET_IPGRE_BROADCAST 932b8c26a33SStephen Hemminger .ndo_open = ipgre_open, 933b8c26a33SStephen Hemminger .ndo_stop = ipgre_close, 934b8c26a33SStephen Hemminger #endif 935c5441932SPravin B Shelar .ndo_start_xmit = ipgre_xmit, 9363e7a1c7cSArnd Bergmann .ndo_siocdevprivate = ip_tunnel_siocdevprivate, 937c5441932SPravin B Shelar .ndo_change_mtu = ip_tunnel_change_mtu, 93898d7fc46SHeiner Kallweit .ndo_get_stats64 = dev_get_tstats64, 9391e99584bSNicolas Dichtel .ndo_get_iflink = ip_tunnel_get_iflink, 940607259a6SChristoph Hellwig .ndo_tunnel_ctl = ipgre_tunnel_ctl, 941b8c26a33SStephen Hemminger }; 942b8c26a33SStephen Hemminger 9436b78f16eSEric Dumazet #define GRE_FEATURES (NETIF_F_SG | \ 9446b78f16eSEric Dumazet NETIF_F_FRAGLIST | \ 9456b78f16eSEric Dumazet NETIF_F_HIGHDMA | \ 9466b78f16eSEric Dumazet NETIF_F_HW_CSUM) 9476b78f16eSEric Dumazet 9481da177e4SLinus Torvalds static void ipgre_tunnel_setup(struct net_device *dev) 9491da177e4SLinus Torvalds { 950b8c26a33SStephen Hemminger dev->netdev_ops = &ipgre_netdev_ops; 9515a455275SNicolas Dichtel dev->type = ARPHRD_IPGRE; 952c5441932SPravin B Shelar ip_tunnel_setup(dev, ipgre_net_id); 953c5441932SPravin B Shelar } 9541da177e4SLinus Torvalds 955c5441932SPravin B Shelar static void __gre_tunnel_init(struct net_device *dev) 956c5441932SPravin B Shelar { 957c5441932SPravin B Shelar struct ip_tunnel *tunnel; 958020e8f60SPeilin Ye __be16 flags; 959c5441932SPravin B Shelar 960c5441932SPravin B Shelar tunnel = netdev_priv(dev); 96195f5c64cSTom Herbert tunnel->tun_hlen = gre_calc_hlen(tunnel->parms.o_flags); 962c5441932SPravin B Shelar tunnel->parms.iph.protocol = IPPROTO_GRE; 963c5441932SPravin B Shelar 9644565e991STom Herbert tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen; 965fdafed45SCong Wang dev->needed_headroom = tunnel->hlen + sizeof(tunnel->parms.iph); 9664565e991STom Herbert 967020e8f60SPeilin Ye dev->features |= GRE_FEATURES | NETIF_F_LLTX; 9686b78f16eSEric Dumazet dev->hw_features |= GRE_FEATURES; 969c5441932SPravin B Shelar 970020e8f60SPeilin Ye flags = tunnel->parms.o_flags; 971020e8f60SPeilin Ye 972020e8f60SPeilin Ye /* TCP offload with GRE SEQ is not supported, nor can we support 2 973020e8f60SPeilin Ye * levels of outer headers requiring an update. 974a0ca153fSAlexander Duyck */ 975020e8f60SPeilin Ye if (flags & TUNNEL_SEQ) 976020e8f60SPeilin Ye return; 977020e8f60SPeilin Ye if (flags & TUNNEL_CSUM && tunnel->encap.type != TUNNEL_ENCAP_NONE) 978020e8f60SPeilin Ye return; 979020e8f60SPeilin Ye 980c5441932SPravin B Shelar dev->features |= NETIF_F_GSO_SOFTWARE; 981c5441932SPravin B Shelar dev->hw_features |= NETIF_F_GSO_SOFTWARE; 982a0ca153fSAlexander Duyck } 983a0ca153fSAlexander Duyck 9841da177e4SLinus Torvalds static int ipgre_tunnel_init(struct net_device *dev) 9851da177e4SLinus Torvalds { 986c5441932SPravin B Shelar struct ip_tunnel *tunnel = netdev_priv(dev); 987c5441932SPravin B Shelar struct iphdr *iph = &tunnel->parms.iph; 9881da177e4SLinus Torvalds 989c5441932SPravin B Shelar __gre_tunnel_init(dev); 9901da177e4SLinus Torvalds 9915a1b7e1aSJakub Kicinski __dev_addr_set(dev, &iph->saddr, 4); 992c5441932SPravin B Shelar memcpy(dev->broadcast, &iph->daddr, 4); 9931da177e4SLinus Torvalds 994c5441932SPravin B Shelar dev->flags = IFF_NOARP; 99502875878SEric Dumazet netif_keep_dst(dev); 996c5441932SPravin B Shelar dev->addr_len = 4; 9971da177e4SLinus Torvalds 998a64b04d8SJiri Benc if (iph->daddr && !tunnel->collect_md) { 9991da177e4SLinus Torvalds #ifdef CONFIG_NET_IPGRE_BROADCAST 1000f97c1e0cSJoe Perches if (ipv4_is_multicast(iph->daddr)) { 10011da177e4SLinus Torvalds if (!iph->saddr) 10021da177e4SLinus Torvalds return -EINVAL; 10031da177e4SLinus Torvalds dev->flags = IFF_BROADCAST; 10043b04dddeSStephen Hemminger dev->header_ops = &ipgre_header_ops; 1005fdafed45SCong Wang dev->hard_header_len = tunnel->hlen + sizeof(*iph); 1006fdafed45SCong Wang dev->needed_headroom = 0; 10071da177e4SLinus Torvalds } 10081da177e4SLinus Torvalds #endif 1009a64b04d8SJiri Benc } else if (!tunnel->collect_md) { 10106a5f44d7STimo Teras dev->header_ops = &ipgre_header_ops; 1011fdafed45SCong Wang dev->hard_header_len = tunnel->hlen + sizeof(*iph); 1012fdafed45SCong Wang dev->needed_headroom = 0; 1013a64b04d8SJiri Benc } 10141da177e4SLinus Torvalds 1015c5441932SPravin B Shelar return ip_tunnel_init(dev); 101660769a5dSEric Dumazet } 101760769a5dSEric Dumazet 10189f57c67cSPravin B Shelar static const struct gre_protocol ipgre_protocol = { 10199f57c67cSPravin B Shelar .handler = gre_rcv, 10209f57c67cSPravin B Shelar .err_handler = gre_err, 10211da177e4SLinus Torvalds }; 10221da177e4SLinus Torvalds 10232c8c1e72SAlexey Dobriyan static int __net_init ipgre_init_net(struct net *net) 102459a4c759SPavel Emelyanov { 1025c5441932SPravin B Shelar return ip_tunnel_init_net(net, ipgre_net_id, &ipgre_link_ops, NULL); 102659a4c759SPavel Emelyanov } 102759a4c759SPavel Emelyanov 1028*9b5b3637SEric Dumazet static void __net_exit ipgre_exit_batch_rtnl(struct list_head *list_net, 1029*9b5b3637SEric Dumazet struct list_head *dev_to_kill) 103059a4c759SPavel Emelyanov { 1031*9b5b3637SEric Dumazet ip_tunnel_delete_nets(list_net, ipgre_net_id, &ipgre_link_ops, 1032*9b5b3637SEric Dumazet dev_to_kill); 103359a4c759SPavel Emelyanov } 103459a4c759SPavel Emelyanov 103559a4c759SPavel Emelyanov static struct pernet_operations ipgre_net_ops = { 103659a4c759SPavel Emelyanov .init = ipgre_init_net, 1037*9b5b3637SEric Dumazet .exit_batch_rtnl = ipgre_exit_batch_rtnl, 1038cfb8fbf2SEric W. Biederman .id = &ipgre_net_id, 1039c5441932SPravin B Shelar .size = sizeof(struct ip_tunnel_net), 104059a4c759SPavel Emelyanov }; 10411da177e4SLinus Torvalds 1042a8b8a889SMatthias Schiffer static int ipgre_tunnel_validate(struct nlattr *tb[], struct nlattr *data[], 1043a8b8a889SMatthias Schiffer struct netlink_ext_ack *extack) 1044c19e654dSHerbert Xu { 1045c19e654dSHerbert Xu __be16 flags; 1046c19e654dSHerbert Xu 1047c19e654dSHerbert Xu if (!data) 1048c19e654dSHerbert Xu return 0; 1049c19e654dSHerbert Xu 1050c19e654dSHerbert Xu flags = 0; 1051c19e654dSHerbert Xu if (data[IFLA_GRE_IFLAGS]) 1052c19e654dSHerbert Xu flags |= nla_get_be16(data[IFLA_GRE_IFLAGS]); 1053c19e654dSHerbert Xu if (data[IFLA_GRE_OFLAGS]) 1054c19e654dSHerbert Xu flags |= nla_get_be16(data[IFLA_GRE_OFLAGS]); 1055c19e654dSHerbert Xu if (flags & (GRE_VERSION|GRE_ROUTING)) 1056c19e654dSHerbert Xu return -EINVAL; 1057c19e654dSHerbert Xu 1058946b636fSJiri Benc if (data[IFLA_GRE_COLLECT_METADATA] && 1059946b636fSJiri Benc data[IFLA_GRE_ENCAP_TYPE] && 1060946b636fSJiri Benc nla_get_u16(data[IFLA_GRE_ENCAP_TYPE]) != TUNNEL_ENCAP_NONE) 1061946b636fSJiri Benc return -EINVAL; 1062946b636fSJiri Benc 1063c19e654dSHerbert Xu return 0; 1064c19e654dSHerbert Xu } 1065c19e654dSHerbert Xu 1066a8b8a889SMatthias Schiffer static int ipgre_tap_validate(struct nlattr *tb[], struct nlattr *data[], 1067a8b8a889SMatthias Schiffer struct netlink_ext_ack *extack) 1068e1a80002SHerbert Xu { 1069e1a80002SHerbert Xu __be32 daddr; 1070e1a80002SHerbert Xu 1071e1a80002SHerbert Xu if (tb[IFLA_ADDRESS]) { 1072e1a80002SHerbert Xu if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN) 1073e1a80002SHerbert Xu return -EINVAL; 1074e1a80002SHerbert Xu if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS]))) 1075e1a80002SHerbert Xu return -EADDRNOTAVAIL; 1076e1a80002SHerbert Xu } 1077e1a80002SHerbert Xu 1078e1a80002SHerbert Xu if (!data) 1079e1a80002SHerbert Xu goto out; 1080e1a80002SHerbert Xu 1081e1a80002SHerbert Xu if (data[IFLA_GRE_REMOTE]) { 1082e1a80002SHerbert Xu memcpy(&daddr, nla_data(data[IFLA_GRE_REMOTE]), 4); 1083e1a80002SHerbert Xu if (!daddr) 1084e1a80002SHerbert Xu return -EINVAL; 1085e1a80002SHerbert Xu } 1086e1a80002SHerbert Xu 1087e1a80002SHerbert Xu out: 1088a8b8a889SMatthias Schiffer return ipgre_tunnel_validate(tb, data, extack); 1089e1a80002SHerbert Xu } 1090e1a80002SHerbert Xu 109184e54fe0SWilliam Tu static int erspan_validate(struct nlattr *tb[], struct nlattr *data[], 109284e54fe0SWilliam Tu struct netlink_ext_ack *extack) 109384e54fe0SWilliam Tu { 109484e54fe0SWilliam Tu __be16 flags = 0; 109584e54fe0SWilliam Tu int ret; 109684e54fe0SWilliam Tu 109784e54fe0SWilliam Tu if (!data) 109884e54fe0SWilliam Tu return 0; 109984e54fe0SWilliam Tu 110084e54fe0SWilliam Tu ret = ipgre_tap_validate(tb, data, extack); 110184e54fe0SWilliam Tu if (ret) 110284e54fe0SWilliam Tu return ret; 110384e54fe0SWilliam Tu 110451fa960dSWilliam Tu if (data[IFLA_GRE_ERSPAN_VER] && 110551fa960dSWilliam Tu nla_get_u8(data[IFLA_GRE_ERSPAN_VER]) == 0) 1106f989d546SWilliam Tu return 0; 1107f989d546SWilliam Tu 1108f989d546SWilliam Tu /* ERSPAN type II/III should only have GRE sequence and key flag */ 11091a66a836SWilliam Tu if (data[IFLA_GRE_OFLAGS]) 111084e54fe0SWilliam Tu flags |= nla_get_be16(data[IFLA_GRE_OFLAGS]); 11111a66a836SWilliam Tu if (data[IFLA_GRE_IFLAGS]) 111284e54fe0SWilliam Tu flags |= nla_get_be16(data[IFLA_GRE_IFLAGS]); 11131a66a836SWilliam Tu if (!data[IFLA_GRE_COLLECT_METADATA] && 11141a66a836SWilliam Tu flags != (GRE_SEQ | GRE_KEY)) 111584e54fe0SWilliam Tu return -EINVAL; 111684e54fe0SWilliam Tu 111784e54fe0SWilliam Tu /* ERSPAN Session ID only has 10-bit. Since we reuse 111884e54fe0SWilliam Tu * 32-bit key field as ID, check it's range. 111984e54fe0SWilliam Tu */ 112084e54fe0SWilliam Tu if (data[IFLA_GRE_IKEY] && 112184e54fe0SWilliam Tu (ntohl(nla_get_be32(data[IFLA_GRE_IKEY])) & ~ID_MASK)) 112284e54fe0SWilliam Tu return -EINVAL; 112384e54fe0SWilliam Tu 112484e54fe0SWilliam Tu if (data[IFLA_GRE_OKEY] && 112584e54fe0SWilliam Tu (ntohl(nla_get_be32(data[IFLA_GRE_OKEY])) & ~ID_MASK)) 112684e54fe0SWilliam Tu return -EINVAL; 112784e54fe0SWilliam Tu 112884e54fe0SWilliam Tu return 0; 112984e54fe0SWilliam Tu } 113084e54fe0SWilliam Tu 113122a59be8SPhilip Prindeville static int ipgre_netlink_parms(struct net_device *dev, 11322e15ea39SPravin B Shelar struct nlattr *data[], 11332e15ea39SPravin B Shelar struct nlattr *tb[], 11349830ad4cSCraig Gallek struct ip_tunnel_parm *parms, 11359830ad4cSCraig Gallek __u32 *fwmark) 1136c19e654dSHerbert Xu { 113722a59be8SPhilip Prindeville struct ip_tunnel *t = netdev_priv(dev); 113822a59be8SPhilip Prindeville 11397bb82d92SHerbert Xu memset(parms, 0, sizeof(*parms)); 1140c19e654dSHerbert Xu 1141c19e654dSHerbert Xu parms->iph.protocol = IPPROTO_GRE; 1142c19e654dSHerbert Xu 1143c19e654dSHerbert Xu if (!data) 114422a59be8SPhilip Prindeville return 0; 1145c19e654dSHerbert Xu 1146c19e654dSHerbert Xu if (data[IFLA_GRE_LINK]) 1147c19e654dSHerbert Xu parms->link = nla_get_u32(data[IFLA_GRE_LINK]); 1148c19e654dSHerbert Xu 1149c19e654dSHerbert Xu if (data[IFLA_GRE_IFLAGS]) 1150c5441932SPravin B Shelar parms->i_flags = gre_flags_to_tnl_flags(nla_get_be16(data[IFLA_GRE_IFLAGS])); 1151c19e654dSHerbert Xu 1152c19e654dSHerbert Xu if (data[IFLA_GRE_OFLAGS]) 1153c5441932SPravin B Shelar parms->o_flags = gre_flags_to_tnl_flags(nla_get_be16(data[IFLA_GRE_OFLAGS])); 1154c19e654dSHerbert Xu 1155c19e654dSHerbert Xu if (data[IFLA_GRE_IKEY]) 1156c19e654dSHerbert Xu parms->i_key = nla_get_be32(data[IFLA_GRE_IKEY]); 1157c19e654dSHerbert Xu 1158c19e654dSHerbert Xu if (data[IFLA_GRE_OKEY]) 1159c19e654dSHerbert Xu parms->o_key = nla_get_be32(data[IFLA_GRE_OKEY]); 1160c19e654dSHerbert Xu 1161c19e654dSHerbert Xu if (data[IFLA_GRE_LOCAL]) 116267b61f6cSJiri Benc parms->iph.saddr = nla_get_in_addr(data[IFLA_GRE_LOCAL]); 1163c19e654dSHerbert Xu 1164c19e654dSHerbert Xu if (data[IFLA_GRE_REMOTE]) 116567b61f6cSJiri Benc parms->iph.daddr = nla_get_in_addr(data[IFLA_GRE_REMOTE]); 1166c19e654dSHerbert Xu 1167c19e654dSHerbert Xu if (data[IFLA_GRE_TTL]) 1168c19e654dSHerbert Xu parms->iph.ttl = nla_get_u8(data[IFLA_GRE_TTL]); 1169c19e654dSHerbert Xu 1170c19e654dSHerbert Xu if (data[IFLA_GRE_TOS]) 1171c19e654dSHerbert Xu parms->iph.tos = nla_get_u8(data[IFLA_GRE_TOS]); 1172c19e654dSHerbert Xu 117322a59be8SPhilip Prindeville if (!data[IFLA_GRE_PMTUDISC] || nla_get_u8(data[IFLA_GRE_PMTUDISC])) { 117422a59be8SPhilip Prindeville if (t->ignore_df) 117522a59be8SPhilip Prindeville return -EINVAL; 1176c19e654dSHerbert Xu parms->iph.frag_off = htons(IP_DF); 117722a59be8SPhilip Prindeville } 11782e15ea39SPravin B Shelar 11792e15ea39SPravin B Shelar if (data[IFLA_GRE_COLLECT_METADATA]) { 11802e15ea39SPravin B Shelar t->collect_md = true; 1181e271c7b4SJiri Benc if (dev->type == ARPHRD_IPGRE) 1182e271c7b4SJiri Benc dev->type = ARPHRD_NONE; 11832e15ea39SPravin B Shelar } 118422a59be8SPhilip Prindeville 118522a59be8SPhilip Prindeville if (data[IFLA_GRE_IGNORE_DF]) { 118622a59be8SPhilip Prindeville if (nla_get_u8(data[IFLA_GRE_IGNORE_DF]) 118722a59be8SPhilip Prindeville && (parms->iph.frag_off & htons(IP_DF))) 118822a59be8SPhilip Prindeville return -EINVAL; 118922a59be8SPhilip Prindeville t->ignore_df = !!nla_get_u8(data[IFLA_GRE_IGNORE_DF]); 119022a59be8SPhilip Prindeville } 119122a59be8SPhilip Prindeville 11929830ad4cSCraig Gallek if (data[IFLA_GRE_FWMARK]) 11939830ad4cSCraig Gallek *fwmark = nla_get_u32(data[IFLA_GRE_FWMARK]); 11949830ad4cSCraig Gallek 1195e1f8f78fSPetr Machata return 0; 1196e1f8f78fSPetr Machata } 1197e1f8f78fSPetr Machata 1198e1f8f78fSPetr Machata static int erspan_netlink_parms(struct net_device *dev, 1199e1f8f78fSPetr Machata struct nlattr *data[], 1200e1f8f78fSPetr Machata struct nlattr *tb[], 1201e1f8f78fSPetr Machata struct ip_tunnel_parm *parms, 1202e1f8f78fSPetr Machata __u32 *fwmark) 1203e1f8f78fSPetr Machata { 1204e1f8f78fSPetr Machata struct ip_tunnel *t = netdev_priv(dev); 1205e1f8f78fSPetr Machata int err; 1206e1f8f78fSPetr Machata 1207e1f8f78fSPetr Machata err = ipgre_netlink_parms(dev, data, tb, parms, fwmark); 1208e1f8f78fSPetr Machata if (err) 1209e1f8f78fSPetr Machata return err; 121032ca98feSPetr Machata if (!data) 121132ca98feSPetr Machata return 0; 1212e1f8f78fSPetr Machata 1213f551c91dSWilliam Tu if (data[IFLA_GRE_ERSPAN_VER]) { 1214f551c91dSWilliam Tu t->erspan_ver = nla_get_u8(data[IFLA_GRE_ERSPAN_VER]); 1215f551c91dSWilliam Tu 1216f989d546SWilliam Tu if (t->erspan_ver > 2) 1217f551c91dSWilliam Tu return -EINVAL; 1218f551c91dSWilliam Tu } 1219f551c91dSWilliam Tu 1220f551c91dSWilliam Tu if (t->erspan_ver == 1) { 122184e54fe0SWilliam Tu if (data[IFLA_GRE_ERSPAN_INDEX]) { 122284e54fe0SWilliam Tu t->index = nla_get_u32(data[IFLA_GRE_ERSPAN_INDEX]); 122384e54fe0SWilliam Tu if (t->index & ~INDEX_MASK) 122484e54fe0SWilliam Tu return -EINVAL; 122584e54fe0SWilliam Tu } 1226f551c91dSWilliam Tu } else if (t->erspan_ver == 2) { 1227f551c91dSWilliam Tu if (data[IFLA_GRE_ERSPAN_DIR]) { 1228f551c91dSWilliam Tu t->dir = nla_get_u8(data[IFLA_GRE_ERSPAN_DIR]); 1229f551c91dSWilliam Tu if (t->dir & ~(DIR_MASK >> DIR_OFFSET)) 1230f551c91dSWilliam Tu return -EINVAL; 1231f551c91dSWilliam Tu } 1232f551c91dSWilliam Tu if (data[IFLA_GRE_ERSPAN_HWID]) { 1233f551c91dSWilliam Tu t->hwid = nla_get_u16(data[IFLA_GRE_ERSPAN_HWID]); 1234f551c91dSWilliam Tu if (t->hwid & ~(HWID_MASK >> HWID_OFFSET)) 1235f551c91dSWilliam Tu return -EINVAL; 1236f551c91dSWilliam Tu } 1237f551c91dSWilliam Tu } 123884e54fe0SWilliam Tu 123922a59be8SPhilip Prindeville return 0; 1240c19e654dSHerbert Xu } 1241c19e654dSHerbert Xu 12424565e991STom Herbert /* This function returns true when ENCAP attributes are present in the nl msg */ 12434565e991STom Herbert static bool ipgre_netlink_encap_parms(struct nlattr *data[], 12444565e991STom Herbert struct ip_tunnel_encap *ipencap) 12454565e991STom Herbert { 12464565e991STom Herbert bool ret = false; 12474565e991STom Herbert 12484565e991STom Herbert memset(ipencap, 0, sizeof(*ipencap)); 12494565e991STom Herbert 12504565e991STom Herbert if (!data) 12514565e991STom Herbert return ret; 12524565e991STom Herbert 12534565e991STom Herbert if (data[IFLA_GRE_ENCAP_TYPE]) { 12544565e991STom Herbert ret = true; 12554565e991STom Herbert ipencap->type = nla_get_u16(data[IFLA_GRE_ENCAP_TYPE]); 12564565e991STom Herbert } 12574565e991STom Herbert 12584565e991STom Herbert if (data[IFLA_GRE_ENCAP_FLAGS]) { 12594565e991STom Herbert ret = true; 12604565e991STom Herbert ipencap->flags = nla_get_u16(data[IFLA_GRE_ENCAP_FLAGS]); 12614565e991STom Herbert } 12624565e991STom Herbert 12634565e991STom Herbert if (data[IFLA_GRE_ENCAP_SPORT]) { 12644565e991STom Herbert ret = true; 12653e97fa70SSabrina Dubroca ipencap->sport = nla_get_be16(data[IFLA_GRE_ENCAP_SPORT]); 12664565e991STom Herbert } 12674565e991STom Herbert 12684565e991STom Herbert if (data[IFLA_GRE_ENCAP_DPORT]) { 12694565e991STom Herbert ret = true; 12703e97fa70SSabrina Dubroca ipencap->dport = nla_get_be16(data[IFLA_GRE_ENCAP_DPORT]); 12714565e991STom Herbert } 12724565e991STom Herbert 12734565e991STom Herbert return ret; 12744565e991STom Herbert } 12754565e991STom Herbert 1276c5441932SPravin B Shelar static int gre_tap_init(struct net_device *dev) 1277e1a80002SHerbert Xu { 1278c5441932SPravin B Shelar __gre_tunnel_init(dev); 1279bec94d43Sstephen hemminger dev->priv_flags |= IFF_LIVE_ADDR_CHANGE; 1280d51711c0SXin Long netif_keep_dst(dev); 1281e1a80002SHerbert Xu 1282c5441932SPravin B Shelar return ip_tunnel_init(dev); 1283e1a80002SHerbert Xu } 1284e1a80002SHerbert Xu 1285c5441932SPravin B Shelar static const struct net_device_ops gre_tap_netdev_ops = { 1286c5441932SPravin B Shelar .ndo_init = gre_tap_init, 1287c5441932SPravin B Shelar .ndo_uninit = ip_tunnel_uninit, 1288c5441932SPravin B Shelar .ndo_start_xmit = gre_tap_xmit, 1289b8c26a33SStephen Hemminger .ndo_set_mac_address = eth_mac_addr, 1290b8c26a33SStephen Hemminger .ndo_validate_addr = eth_validate_addr, 1291c5441932SPravin B Shelar .ndo_change_mtu = ip_tunnel_change_mtu, 129298d7fc46SHeiner Kallweit .ndo_get_stats64 = dev_get_tstats64, 12931e99584bSNicolas Dichtel .ndo_get_iflink = ip_tunnel_get_iflink, 1294fc4099f1SPravin B Shelar .ndo_fill_metadata_dst = gre_fill_metadata_dst, 1295b8c26a33SStephen Hemminger }; 1296b8c26a33SStephen Hemminger 129784e54fe0SWilliam Tu static int erspan_tunnel_init(struct net_device *dev) 129884e54fe0SWilliam Tu { 129984e54fe0SWilliam Tu struct ip_tunnel *tunnel = netdev_priv(dev); 130084e54fe0SWilliam Tu 1301f989d546SWilliam Tu if (tunnel->erspan_ver == 0) 1302f989d546SWilliam Tu tunnel->tun_hlen = 4; /* 4-byte GRE hdr. */ 1303f989d546SWilliam Tu else 1304f989d546SWilliam Tu tunnel->tun_hlen = 8; /* 8-byte GRE hdr. */ 1305f989d546SWilliam Tu 130684e54fe0SWilliam Tu tunnel->parms.iph.protocol = IPPROTO_GRE; 1307c122fda2SXin Long tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen + 1308f551c91dSWilliam Tu erspan_hdr_len(tunnel->erspan_ver); 130984e54fe0SWilliam Tu 131084e54fe0SWilliam Tu dev->features |= GRE_FEATURES; 131184e54fe0SWilliam Tu dev->hw_features |= GRE_FEATURES; 131284e54fe0SWilliam Tu dev->priv_flags |= IFF_LIVE_ADDR_CHANGE; 1313c84bed44SXin Long netif_keep_dst(dev); 131484e54fe0SWilliam Tu 131584e54fe0SWilliam Tu return ip_tunnel_init(dev); 131684e54fe0SWilliam Tu } 131784e54fe0SWilliam Tu 131884e54fe0SWilliam Tu static const struct net_device_ops erspan_netdev_ops = { 131984e54fe0SWilliam Tu .ndo_init = erspan_tunnel_init, 132084e54fe0SWilliam Tu .ndo_uninit = ip_tunnel_uninit, 132184e54fe0SWilliam Tu .ndo_start_xmit = erspan_xmit, 132284e54fe0SWilliam Tu .ndo_set_mac_address = eth_mac_addr, 132384e54fe0SWilliam Tu .ndo_validate_addr = eth_validate_addr, 132484e54fe0SWilliam Tu .ndo_change_mtu = ip_tunnel_change_mtu, 132598d7fc46SHeiner Kallweit .ndo_get_stats64 = dev_get_tstats64, 132684e54fe0SWilliam Tu .ndo_get_iflink = ip_tunnel_get_iflink, 132784e54fe0SWilliam Tu .ndo_fill_metadata_dst = gre_fill_metadata_dst, 132884e54fe0SWilliam Tu }; 132984e54fe0SWilliam Tu 1330e1a80002SHerbert Xu static void ipgre_tap_setup(struct net_device *dev) 1331e1a80002SHerbert Xu { 1332e1a80002SHerbert Xu ether_setup(dev); 1333cfddd4c3SXin Long dev->max_mtu = 0; 1334c5441932SPravin B Shelar dev->netdev_ops = &gre_tap_netdev_ops; 1335d13b161cSJiri Benc dev->priv_flags &= ~IFF_TX_SKB_SHARING; 1336f8c1b7ceSstephen hemminger dev->priv_flags |= IFF_LIVE_ADDR_CHANGE; 1337c5441932SPravin B Shelar ip_tunnel_setup(dev, gre_tap_net_id); 1338e1a80002SHerbert Xu } 1339e1a80002SHerbert Xu 1340e1f8f78fSPetr Machata static int 1341e1f8f78fSPetr Machata ipgre_newlink_encap_setup(struct net_device *dev, struct nlattr *data[]) 1342c19e654dSHerbert Xu { 13434565e991STom Herbert struct ip_tunnel_encap ipencap; 13444565e991STom Herbert 13454565e991STom Herbert if (ipgre_netlink_encap_parms(data, &ipencap)) { 13464565e991STom Herbert struct ip_tunnel *t = netdev_priv(dev); 1347e1f8f78fSPetr Machata int err = ip_tunnel_encap_setup(t, &ipencap); 13484565e991STom Herbert 13494565e991STom Herbert if (err < 0) 13504565e991STom Herbert return err; 13514565e991STom Herbert } 1352c19e654dSHerbert Xu 1353e1f8f78fSPetr Machata return 0; 1354e1f8f78fSPetr Machata } 1355e1f8f78fSPetr Machata 1356e1f8f78fSPetr Machata static int ipgre_newlink(struct net *src_net, struct net_device *dev, 1357e1f8f78fSPetr Machata struct nlattr *tb[], struct nlattr *data[], 1358e1f8f78fSPetr Machata struct netlink_ext_ack *extack) 1359e1f8f78fSPetr Machata { 1360e1f8f78fSPetr Machata struct ip_tunnel_parm p; 1361e1f8f78fSPetr Machata __u32 fwmark = 0; 1362e1f8f78fSPetr Machata int err; 1363e1f8f78fSPetr Machata 1364e1f8f78fSPetr Machata err = ipgre_newlink_encap_setup(dev, data); 1365e1f8f78fSPetr Machata if (err) 1366e1f8f78fSPetr Machata return err; 1367e1f8f78fSPetr Machata 13689830ad4cSCraig Gallek err = ipgre_netlink_parms(dev, data, tb, &p, &fwmark); 136922a59be8SPhilip Prindeville if (err < 0) 137022a59be8SPhilip Prindeville return err; 13719830ad4cSCraig Gallek return ip_tunnel_newlink(dev, tb, &p, fwmark); 1372c19e654dSHerbert Xu } 1373c19e654dSHerbert Xu 1374e1f8f78fSPetr Machata static int erspan_newlink(struct net *src_net, struct net_device *dev, 1375e1f8f78fSPetr Machata struct nlattr *tb[], struct nlattr *data[], 1376e1f8f78fSPetr Machata struct netlink_ext_ack *extack) 1377e1f8f78fSPetr Machata { 1378e1f8f78fSPetr Machata struct ip_tunnel_parm p; 1379e1f8f78fSPetr Machata __u32 fwmark = 0; 1380e1f8f78fSPetr Machata int err; 1381e1f8f78fSPetr Machata 1382e1f8f78fSPetr Machata err = ipgre_newlink_encap_setup(dev, data); 1383e1f8f78fSPetr Machata if (err) 1384e1f8f78fSPetr Machata return err; 1385e1f8f78fSPetr Machata 1386e1f8f78fSPetr Machata err = erspan_netlink_parms(dev, data, tb, &p, &fwmark); 1387e1f8f78fSPetr Machata if (err) 1388e1f8f78fSPetr Machata return err; 1389e1f8f78fSPetr Machata return ip_tunnel_newlink(dev, tb, &p, fwmark); 1390e1f8f78fSPetr Machata } 1391e1f8f78fSPetr Machata 1392c19e654dSHerbert Xu static int ipgre_changelink(struct net_device *dev, struct nlattr *tb[], 1393ad744b22SMatthias Schiffer struct nlattr *data[], 1394ad744b22SMatthias Schiffer struct netlink_ext_ack *extack) 1395c19e654dSHerbert Xu { 13969830ad4cSCraig Gallek struct ip_tunnel *t = netdev_priv(dev); 13979830ad4cSCraig Gallek __u32 fwmark = t->fwmark; 1398dd9d598cSXin Long struct ip_tunnel_parm p; 139922a59be8SPhilip Prindeville int err; 14004565e991STom Herbert 1401e1f8f78fSPetr Machata err = ipgre_newlink_encap_setup(dev, data); 1402e1f8f78fSPetr Machata if (err) 14034565e991STom Herbert return err; 1404c19e654dSHerbert Xu 14059830ad4cSCraig Gallek err = ipgre_netlink_parms(dev, data, tb, &p, &fwmark); 140622a59be8SPhilip Prindeville if (err < 0) 140722a59be8SPhilip Prindeville return err; 1408dd9d598cSXin Long 1409dd9d598cSXin Long err = ip_tunnel_changelink(dev, tb, &p, fwmark); 1410dd9d598cSXin Long if (err < 0) 1411dd9d598cSXin Long return err; 1412dd9d598cSXin Long 1413dd9d598cSXin Long t->parms.i_flags = p.i_flags; 1414dd9d598cSXin Long t->parms.o_flags = p.o_flags; 1415dd9d598cSXin Long 1416dd9d598cSXin Long ipgre_link_update(dev, !tb[IFLA_MTU]); 1417dd9d598cSXin Long 1418dd9d598cSXin Long return 0; 1419c19e654dSHerbert Xu } 1420c19e654dSHerbert Xu 1421e1f8f78fSPetr Machata static int erspan_changelink(struct net_device *dev, struct nlattr *tb[], 1422e1f8f78fSPetr Machata struct nlattr *data[], 1423e1f8f78fSPetr Machata struct netlink_ext_ack *extack) 1424e1f8f78fSPetr Machata { 1425e1f8f78fSPetr Machata struct ip_tunnel *t = netdev_priv(dev); 1426e1f8f78fSPetr Machata __u32 fwmark = t->fwmark; 1427e1f8f78fSPetr Machata struct ip_tunnel_parm p; 1428e1f8f78fSPetr Machata int err; 1429e1f8f78fSPetr Machata 1430e1f8f78fSPetr Machata err = ipgre_newlink_encap_setup(dev, data); 1431e1f8f78fSPetr Machata if (err) 1432e1f8f78fSPetr Machata return err; 1433e1f8f78fSPetr Machata 1434e1f8f78fSPetr Machata err = erspan_netlink_parms(dev, data, tb, &p, &fwmark); 1435e1f8f78fSPetr Machata if (err < 0) 1436e1f8f78fSPetr Machata return err; 1437e1f8f78fSPetr Machata 1438e1f8f78fSPetr Machata err = ip_tunnel_changelink(dev, tb, &p, fwmark); 1439e1f8f78fSPetr Machata if (err < 0) 1440e1f8f78fSPetr Machata return err; 1441e1f8f78fSPetr Machata 1442e1f8f78fSPetr Machata t->parms.i_flags = p.i_flags; 1443e1f8f78fSPetr Machata t->parms.o_flags = p.o_flags; 1444e1f8f78fSPetr Machata 1445e1f8f78fSPetr Machata return 0; 1446e1f8f78fSPetr Machata } 1447e1f8f78fSPetr Machata 1448c19e654dSHerbert Xu static size_t ipgre_get_size(const struct net_device *dev) 1449c19e654dSHerbert Xu { 1450c19e654dSHerbert Xu return 1451c19e654dSHerbert Xu /* IFLA_GRE_LINK */ 1452c19e654dSHerbert Xu nla_total_size(4) + 1453c19e654dSHerbert Xu /* IFLA_GRE_IFLAGS */ 1454c19e654dSHerbert Xu nla_total_size(2) + 1455c19e654dSHerbert Xu /* IFLA_GRE_OFLAGS */ 1456c19e654dSHerbert Xu nla_total_size(2) + 1457c19e654dSHerbert Xu /* IFLA_GRE_IKEY */ 1458c19e654dSHerbert Xu nla_total_size(4) + 1459c19e654dSHerbert Xu /* IFLA_GRE_OKEY */ 1460c19e654dSHerbert Xu nla_total_size(4) + 1461c19e654dSHerbert Xu /* IFLA_GRE_LOCAL */ 1462c19e654dSHerbert Xu nla_total_size(4) + 1463c19e654dSHerbert Xu /* IFLA_GRE_REMOTE */ 1464c19e654dSHerbert Xu nla_total_size(4) + 1465c19e654dSHerbert Xu /* IFLA_GRE_TTL */ 1466c19e654dSHerbert Xu nla_total_size(1) + 1467c19e654dSHerbert Xu /* IFLA_GRE_TOS */ 1468c19e654dSHerbert Xu nla_total_size(1) + 1469c19e654dSHerbert Xu /* IFLA_GRE_PMTUDISC */ 1470c19e654dSHerbert Xu nla_total_size(1) + 14714565e991STom Herbert /* IFLA_GRE_ENCAP_TYPE */ 14724565e991STom Herbert nla_total_size(2) + 14734565e991STom Herbert /* IFLA_GRE_ENCAP_FLAGS */ 14744565e991STom Herbert nla_total_size(2) + 14754565e991STom Herbert /* IFLA_GRE_ENCAP_SPORT */ 14764565e991STom Herbert nla_total_size(2) + 14774565e991STom Herbert /* IFLA_GRE_ENCAP_DPORT */ 14784565e991STom Herbert nla_total_size(2) + 14792e15ea39SPravin B Shelar /* IFLA_GRE_COLLECT_METADATA */ 14802e15ea39SPravin B Shelar nla_total_size(0) + 148122a59be8SPhilip Prindeville /* IFLA_GRE_IGNORE_DF */ 148222a59be8SPhilip Prindeville nla_total_size(1) + 14839830ad4cSCraig Gallek /* IFLA_GRE_FWMARK */ 14849830ad4cSCraig Gallek nla_total_size(4) + 148584e54fe0SWilliam Tu /* IFLA_GRE_ERSPAN_INDEX */ 148684e54fe0SWilliam Tu nla_total_size(4) + 1487f551c91dSWilliam Tu /* IFLA_GRE_ERSPAN_VER */ 1488f551c91dSWilliam Tu nla_total_size(1) + 1489f551c91dSWilliam Tu /* IFLA_GRE_ERSPAN_DIR */ 1490f551c91dSWilliam Tu nla_total_size(1) + 1491f551c91dSWilliam Tu /* IFLA_GRE_ERSPAN_HWID */ 1492f551c91dSWilliam Tu nla_total_size(2) + 1493c19e654dSHerbert Xu 0; 1494c19e654dSHerbert Xu } 1495c19e654dSHerbert Xu 1496c19e654dSHerbert Xu static int ipgre_fill_info(struct sk_buff *skb, const struct net_device *dev) 1497c19e654dSHerbert Xu { 1498c19e654dSHerbert Xu struct ip_tunnel *t = netdev_priv(dev); 1499c19e654dSHerbert Xu struct ip_tunnel_parm *p = &t->parms; 1500feaf5c79SLorenzo Bianconi __be16 o_flags = p->o_flags; 1501feaf5c79SLorenzo Bianconi 1502f3756b79SDavid S. Miller if (nla_put_u32(skb, IFLA_GRE_LINK, p->link) || 150395f5c64cSTom Herbert nla_put_be16(skb, IFLA_GRE_IFLAGS, 150495f5c64cSTom Herbert gre_tnl_flags_to_gre_flags(p->i_flags)) || 150595f5c64cSTom Herbert nla_put_be16(skb, IFLA_GRE_OFLAGS, 1506feaf5c79SLorenzo Bianconi gre_tnl_flags_to_gre_flags(o_flags)) || 1507f3756b79SDavid S. Miller nla_put_be32(skb, IFLA_GRE_IKEY, p->i_key) || 1508f3756b79SDavid S. Miller nla_put_be32(skb, IFLA_GRE_OKEY, p->o_key) || 1509930345eaSJiri Benc nla_put_in_addr(skb, IFLA_GRE_LOCAL, p->iph.saddr) || 1510930345eaSJiri Benc nla_put_in_addr(skb, IFLA_GRE_REMOTE, p->iph.daddr) || 1511f3756b79SDavid S. Miller nla_put_u8(skb, IFLA_GRE_TTL, p->iph.ttl) || 1512f3756b79SDavid S. Miller nla_put_u8(skb, IFLA_GRE_TOS, p->iph.tos) || 1513f3756b79SDavid S. Miller nla_put_u8(skb, IFLA_GRE_PMTUDISC, 15149830ad4cSCraig Gallek !!(p->iph.frag_off & htons(IP_DF))) || 15159830ad4cSCraig Gallek nla_put_u32(skb, IFLA_GRE_FWMARK, t->fwmark)) 1516f3756b79SDavid S. Miller goto nla_put_failure; 15174565e991STom Herbert 15184565e991STom Herbert if (nla_put_u16(skb, IFLA_GRE_ENCAP_TYPE, 15194565e991STom Herbert t->encap.type) || 15203e97fa70SSabrina Dubroca nla_put_be16(skb, IFLA_GRE_ENCAP_SPORT, 15214565e991STom Herbert t->encap.sport) || 15223e97fa70SSabrina Dubroca nla_put_be16(skb, IFLA_GRE_ENCAP_DPORT, 15234565e991STom Herbert t->encap.dport) || 15244565e991STom Herbert nla_put_u16(skb, IFLA_GRE_ENCAP_FLAGS, 1525e1b2cb65STom Herbert t->encap.flags)) 15264565e991STom Herbert goto nla_put_failure; 15274565e991STom Herbert 152822a59be8SPhilip Prindeville if (nla_put_u8(skb, IFLA_GRE_IGNORE_DF, t->ignore_df)) 152922a59be8SPhilip Prindeville goto nla_put_failure; 153022a59be8SPhilip Prindeville 15312e15ea39SPravin B Shelar if (t->collect_md) { 15322e15ea39SPravin B Shelar if (nla_put_flag(skb, IFLA_GRE_COLLECT_METADATA)) 15332e15ea39SPravin B Shelar goto nla_put_failure; 15342e15ea39SPravin B Shelar } 15352e15ea39SPravin B Shelar 1536c19e654dSHerbert Xu return 0; 1537c19e654dSHerbert Xu 1538c19e654dSHerbert Xu nla_put_failure: 1539c19e654dSHerbert Xu return -EMSGSIZE; 1540c19e654dSHerbert Xu } 1541c19e654dSHerbert Xu 1542ee496694SHangbin Liu static int erspan_fill_info(struct sk_buff *skb, const struct net_device *dev) 1543ee496694SHangbin Liu { 1544ee496694SHangbin Liu struct ip_tunnel *t = netdev_priv(dev); 1545ee496694SHangbin Liu 1546ee496694SHangbin Liu if (t->erspan_ver <= 2) { 1547ee496694SHangbin Liu if (t->erspan_ver != 0 && !t->collect_md) 1548ee496694SHangbin Liu t->parms.o_flags |= TUNNEL_KEY; 1549ee496694SHangbin Liu 1550ee496694SHangbin Liu if (nla_put_u8(skb, IFLA_GRE_ERSPAN_VER, t->erspan_ver)) 1551ee496694SHangbin Liu goto nla_put_failure; 1552ee496694SHangbin Liu 1553ee496694SHangbin Liu if (t->erspan_ver == 1) { 1554ee496694SHangbin Liu if (nla_put_u32(skb, IFLA_GRE_ERSPAN_INDEX, t->index)) 1555ee496694SHangbin Liu goto nla_put_failure; 1556ee496694SHangbin Liu } else if (t->erspan_ver == 2) { 1557ee496694SHangbin Liu if (nla_put_u8(skb, IFLA_GRE_ERSPAN_DIR, t->dir)) 1558ee496694SHangbin Liu goto nla_put_failure; 1559ee496694SHangbin Liu if (nla_put_u16(skb, IFLA_GRE_ERSPAN_HWID, t->hwid)) 1560ee496694SHangbin Liu goto nla_put_failure; 1561ee496694SHangbin Liu } 1562ee496694SHangbin Liu } 1563ee496694SHangbin Liu 1564ee496694SHangbin Liu return ipgre_fill_info(skb, dev); 1565ee496694SHangbin Liu 1566ee496694SHangbin Liu nla_put_failure: 1567ee496694SHangbin Liu return -EMSGSIZE; 1568ee496694SHangbin Liu } 1569ee496694SHangbin Liu 157084e54fe0SWilliam Tu static void erspan_setup(struct net_device *dev) 157184e54fe0SWilliam Tu { 157284581bdaSXin Long struct ip_tunnel *t = netdev_priv(dev); 157384581bdaSXin Long 157484e54fe0SWilliam Tu ether_setup(dev); 15750e141f75SHaishuang Yan dev->max_mtu = 0; 157684e54fe0SWilliam Tu dev->netdev_ops = &erspan_netdev_ops; 157784e54fe0SWilliam Tu dev->priv_flags &= ~IFF_TX_SKB_SHARING; 157884e54fe0SWilliam Tu dev->priv_flags |= IFF_LIVE_ADDR_CHANGE; 157984e54fe0SWilliam Tu ip_tunnel_setup(dev, erspan_net_id); 158084581bdaSXin Long t->erspan_ver = 1; 158184e54fe0SWilliam Tu } 158284e54fe0SWilliam Tu 1583c19e654dSHerbert Xu static const struct nla_policy ipgre_policy[IFLA_GRE_MAX + 1] = { 1584c19e654dSHerbert Xu [IFLA_GRE_LINK] = { .type = NLA_U32 }, 1585c19e654dSHerbert Xu [IFLA_GRE_IFLAGS] = { .type = NLA_U16 }, 1586c19e654dSHerbert Xu [IFLA_GRE_OFLAGS] = { .type = NLA_U16 }, 1587c19e654dSHerbert Xu [IFLA_GRE_IKEY] = { .type = NLA_U32 }, 1588c19e654dSHerbert Xu [IFLA_GRE_OKEY] = { .type = NLA_U32 }, 1589c593642cSPankaj Bharadiya [IFLA_GRE_LOCAL] = { .len = sizeof_field(struct iphdr, saddr) }, 1590c593642cSPankaj Bharadiya [IFLA_GRE_REMOTE] = { .len = sizeof_field(struct iphdr, daddr) }, 1591c19e654dSHerbert Xu [IFLA_GRE_TTL] = { .type = NLA_U8 }, 1592c19e654dSHerbert Xu [IFLA_GRE_TOS] = { .type = NLA_U8 }, 1593c19e654dSHerbert Xu [IFLA_GRE_PMTUDISC] = { .type = NLA_U8 }, 15944565e991STom Herbert [IFLA_GRE_ENCAP_TYPE] = { .type = NLA_U16 }, 15954565e991STom Herbert [IFLA_GRE_ENCAP_FLAGS] = { .type = NLA_U16 }, 15964565e991STom Herbert [IFLA_GRE_ENCAP_SPORT] = { .type = NLA_U16 }, 15974565e991STom Herbert [IFLA_GRE_ENCAP_DPORT] = { .type = NLA_U16 }, 15982e15ea39SPravin B Shelar [IFLA_GRE_COLLECT_METADATA] = { .type = NLA_FLAG }, 159922a59be8SPhilip Prindeville [IFLA_GRE_IGNORE_DF] = { .type = NLA_U8 }, 16009830ad4cSCraig Gallek [IFLA_GRE_FWMARK] = { .type = NLA_U32 }, 160184e54fe0SWilliam Tu [IFLA_GRE_ERSPAN_INDEX] = { .type = NLA_U32 }, 1602f551c91dSWilliam Tu [IFLA_GRE_ERSPAN_VER] = { .type = NLA_U8 }, 1603f551c91dSWilliam Tu [IFLA_GRE_ERSPAN_DIR] = { .type = NLA_U8 }, 1604f551c91dSWilliam Tu [IFLA_GRE_ERSPAN_HWID] = { .type = NLA_U16 }, 1605c19e654dSHerbert Xu }; 1606c19e654dSHerbert Xu 1607c19e654dSHerbert Xu static struct rtnl_link_ops ipgre_link_ops __read_mostly = { 1608c19e654dSHerbert Xu .kind = "gre", 1609c19e654dSHerbert Xu .maxtype = IFLA_GRE_MAX, 1610c19e654dSHerbert Xu .policy = ipgre_policy, 1611c19e654dSHerbert Xu .priv_size = sizeof(struct ip_tunnel), 1612c19e654dSHerbert Xu .setup = ipgre_tunnel_setup, 1613c19e654dSHerbert Xu .validate = ipgre_tunnel_validate, 1614c19e654dSHerbert Xu .newlink = ipgre_newlink, 1615c19e654dSHerbert Xu .changelink = ipgre_changelink, 1616c5441932SPravin B Shelar .dellink = ip_tunnel_dellink, 1617c19e654dSHerbert Xu .get_size = ipgre_get_size, 1618c19e654dSHerbert Xu .fill_info = ipgre_fill_info, 16191728d4faSNicolas Dichtel .get_link_net = ip_tunnel_get_link_net, 1620c19e654dSHerbert Xu }; 1621c19e654dSHerbert Xu 1622e1a80002SHerbert Xu static struct rtnl_link_ops ipgre_tap_ops __read_mostly = { 1623e1a80002SHerbert Xu .kind = "gretap", 1624e1a80002SHerbert Xu .maxtype = IFLA_GRE_MAX, 1625e1a80002SHerbert Xu .policy = ipgre_policy, 1626e1a80002SHerbert Xu .priv_size = sizeof(struct ip_tunnel), 1627e1a80002SHerbert Xu .setup = ipgre_tap_setup, 1628e1a80002SHerbert Xu .validate = ipgre_tap_validate, 1629e1a80002SHerbert Xu .newlink = ipgre_newlink, 1630e1a80002SHerbert Xu .changelink = ipgre_changelink, 1631c5441932SPravin B Shelar .dellink = ip_tunnel_dellink, 1632e1a80002SHerbert Xu .get_size = ipgre_get_size, 1633e1a80002SHerbert Xu .fill_info = ipgre_fill_info, 16341728d4faSNicolas Dichtel .get_link_net = ip_tunnel_get_link_net, 1635e1a80002SHerbert Xu }; 1636e1a80002SHerbert Xu 163784e54fe0SWilliam Tu static struct rtnl_link_ops erspan_link_ops __read_mostly = { 163884e54fe0SWilliam Tu .kind = "erspan", 163984e54fe0SWilliam Tu .maxtype = IFLA_GRE_MAX, 164084e54fe0SWilliam Tu .policy = ipgre_policy, 164184e54fe0SWilliam Tu .priv_size = sizeof(struct ip_tunnel), 164284e54fe0SWilliam Tu .setup = erspan_setup, 164384e54fe0SWilliam Tu .validate = erspan_validate, 1644e1f8f78fSPetr Machata .newlink = erspan_newlink, 1645e1f8f78fSPetr Machata .changelink = erspan_changelink, 164684e54fe0SWilliam Tu .dellink = ip_tunnel_dellink, 164784e54fe0SWilliam Tu .get_size = ipgre_get_size, 1648ee496694SHangbin Liu .fill_info = erspan_fill_info, 164984e54fe0SWilliam Tu .get_link_net = ip_tunnel_get_link_net, 165084e54fe0SWilliam Tu }; 165184e54fe0SWilliam Tu 1652b2acd1dcSPravin B Shelar struct net_device *gretap_fb_dev_create(struct net *net, const char *name, 1653b2acd1dcSPravin B Shelar u8 name_assign_type) 1654b2acd1dcSPravin B Shelar { 1655b2acd1dcSPravin B Shelar struct nlattr *tb[IFLA_MAX + 1]; 1656b2acd1dcSPravin B Shelar struct net_device *dev; 1657106da663SNicolas Dichtel LIST_HEAD(list_kill); 1658b2acd1dcSPravin B Shelar struct ip_tunnel *t; 1659b2acd1dcSPravin B Shelar int err; 1660b2acd1dcSPravin B Shelar 1661b2acd1dcSPravin B Shelar memset(&tb, 0, sizeof(tb)); 1662b2acd1dcSPravin B Shelar 1663b2acd1dcSPravin B Shelar dev = rtnl_create_link(net, name, name_assign_type, 1664d0522f1cSDavid Ahern &ipgre_tap_ops, tb, NULL); 1665b2acd1dcSPravin B Shelar if (IS_ERR(dev)) 1666b2acd1dcSPravin B Shelar return dev; 1667b2acd1dcSPravin B Shelar 1668b2acd1dcSPravin B Shelar /* Configure flow based GRE device. */ 1669b2acd1dcSPravin B Shelar t = netdev_priv(dev); 1670b2acd1dcSPravin B Shelar t->collect_md = true; 1671b2acd1dcSPravin B Shelar 16727a3f4a18SMatthias Schiffer err = ipgre_newlink(net, dev, tb, NULL, NULL); 1673106da663SNicolas Dichtel if (err < 0) { 1674106da663SNicolas Dichtel free_netdev(dev); 1675106da663SNicolas Dichtel return ERR_PTR(err); 1676106da663SNicolas Dichtel } 16777e059158SDavid Wragg 16787e059158SDavid Wragg /* openvswitch users expect packet sizes to be unrestricted, 16797e059158SDavid Wragg * so set the largest MTU we can. 16807e059158SDavid Wragg */ 16817e059158SDavid Wragg err = __ip_tunnel_change_mtu(dev, IP_MAX_MTU, false); 16827e059158SDavid Wragg if (err) 16837e059158SDavid Wragg goto out; 16847e059158SDavid Wragg 16851d997f10SHangbin Liu err = rtnl_configure_link(dev, NULL, 0, NULL); 1686da6f1da8SNicolas Dichtel if (err < 0) 1687da6f1da8SNicolas Dichtel goto out; 1688da6f1da8SNicolas Dichtel 1689b2acd1dcSPravin B Shelar return dev; 1690b2acd1dcSPravin B Shelar out: 1691106da663SNicolas Dichtel ip_tunnel_dellink(dev, &list_kill); 1692106da663SNicolas Dichtel unregister_netdevice_many(&list_kill); 1693b2acd1dcSPravin B Shelar return ERR_PTR(err); 1694b2acd1dcSPravin B Shelar } 1695b2acd1dcSPravin B Shelar EXPORT_SYMBOL_GPL(gretap_fb_dev_create); 1696b2acd1dcSPravin B Shelar 1697c5441932SPravin B Shelar static int __net_init ipgre_tap_init_net(struct net *net) 1698c5441932SPravin B Shelar { 16992e15ea39SPravin B Shelar return ip_tunnel_init_net(net, gre_tap_net_id, &ipgre_tap_ops, "gretap0"); 1700c5441932SPravin B Shelar } 1701c5441932SPravin B Shelar 1702*9b5b3637SEric Dumazet static void __net_exit ipgre_tap_exit_batch_rtnl(struct list_head *list_net, 1703*9b5b3637SEric Dumazet struct list_head *dev_to_kill) 1704c5441932SPravin B Shelar { 1705*9b5b3637SEric Dumazet ip_tunnel_delete_nets(list_net, gre_tap_net_id, &ipgre_tap_ops, 1706*9b5b3637SEric Dumazet dev_to_kill); 1707c5441932SPravin B Shelar } 1708c5441932SPravin B Shelar 1709c5441932SPravin B Shelar static struct pernet_operations ipgre_tap_net_ops = { 1710c5441932SPravin B Shelar .init = ipgre_tap_init_net, 1711*9b5b3637SEric Dumazet .exit_batch_rtnl = ipgre_tap_exit_batch_rtnl, 1712c5441932SPravin B Shelar .id = &gre_tap_net_id, 1713c5441932SPravin B Shelar .size = sizeof(struct ip_tunnel_net), 1714c5441932SPravin B Shelar }; 17151da177e4SLinus Torvalds 171684e54fe0SWilliam Tu static int __net_init erspan_init_net(struct net *net) 171784e54fe0SWilliam Tu { 171884e54fe0SWilliam Tu return ip_tunnel_init_net(net, erspan_net_id, 171984e54fe0SWilliam Tu &erspan_link_ops, "erspan0"); 172084e54fe0SWilliam Tu } 172184e54fe0SWilliam Tu 1722*9b5b3637SEric Dumazet static void __net_exit erspan_exit_batch_rtnl(struct list_head *net_list, 1723*9b5b3637SEric Dumazet struct list_head *dev_to_kill) 172484e54fe0SWilliam Tu { 1725*9b5b3637SEric Dumazet ip_tunnel_delete_nets(net_list, erspan_net_id, &erspan_link_ops, 1726*9b5b3637SEric Dumazet dev_to_kill); 172784e54fe0SWilliam Tu } 172884e54fe0SWilliam Tu 172984e54fe0SWilliam Tu static struct pernet_operations erspan_net_ops = { 173084e54fe0SWilliam Tu .init = erspan_init_net, 1731*9b5b3637SEric Dumazet .exit_batch_rtnl = erspan_exit_batch_rtnl, 173284e54fe0SWilliam Tu .id = &erspan_net_id, 173384e54fe0SWilliam Tu .size = sizeof(struct ip_tunnel_net), 173484e54fe0SWilliam Tu }; 173584e54fe0SWilliam Tu 17361da177e4SLinus Torvalds static int __init ipgre_init(void) 17371da177e4SLinus Torvalds { 17381da177e4SLinus Torvalds int err; 17391da177e4SLinus Torvalds 1740058bd4d2SJoe Perches pr_info("GRE over IPv4 tunneling driver\n"); 17411da177e4SLinus Torvalds 1742cfb8fbf2SEric W. Biederman err = register_pernet_device(&ipgre_net_ops); 174359a4c759SPavel Emelyanov if (err < 0) 1744c2892f02SAlexey Dobriyan return err; 1745c2892f02SAlexey Dobriyan 1746c5441932SPravin B Shelar err = register_pernet_device(&ipgre_tap_net_ops); 1747c5441932SPravin B Shelar if (err < 0) 1748e3d0328cSWilliam Tu goto pnet_tap_failed; 1749c5441932SPravin B Shelar 175084e54fe0SWilliam Tu err = register_pernet_device(&erspan_net_ops); 175184e54fe0SWilliam Tu if (err < 0) 175284e54fe0SWilliam Tu goto pnet_erspan_failed; 175384e54fe0SWilliam Tu 17549f57c67cSPravin B Shelar err = gre_add_protocol(&ipgre_protocol, GREPROTO_CISCO); 1755c2892f02SAlexey Dobriyan if (err < 0) { 1756058bd4d2SJoe Perches pr_info("%s: can't add protocol\n", __func__); 1757c2892f02SAlexey Dobriyan goto add_proto_failed; 1758c2892f02SAlexey Dobriyan } 17597daa0004SPavel Emelyanov 1760c19e654dSHerbert Xu err = rtnl_link_register(&ipgre_link_ops); 1761c19e654dSHerbert Xu if (err < 0) 1762c19e654dSHerbert Xu goto rtnl_link_failed; 1763c19e654dSHerbert Xu 1764e1a80002SHerbert Xu err = rtnl_link_register(&ipgre_tap_ops); 1765e1a80002SHerbert Xu if (err < 0) 1766e1a80002SHerbert Xu goto tap_ops_failed; 1767e1a80002SHerbert Xu 176884e54fe0SWilliam Tu err = rtnl_link_register(&erspan_link_ops); 176984e54fe0SWilliam Tu if (err < 0) 177084e54fe0SWilliam Tu goto erspan_link_failed; 177184e54fe0SWilliam Tu 1772c5441932SPravin B Shelar return 0; 1773c19e654dSHerbert Xu 177484e54fe0SWilliam Tu erspan_link_failed: 177584e54fe0SWilliam Tu rtnl_link_unregister(&ipgre_tap_ops); 1776e1a80002SHerbert Xu tap_ops_failed: 1777e1a80002SHerbert Xu rtnl_link_unregister(&ipgre_link_ops); 1778c19e654dSHerbert Xu rtnl_link_failed: 17799f57c67cSPravin B Shelar gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO); 1780c2892f02SAlexey Dobriyan add_proto_failed: 178184e54fe0SWilliam Tu unregister_pernet_device(&erspan_net_ops); 178284e54fe0SWilliam Tu pnet_erspan_failed: 1783c5441932SPravin B Shelar unregister_pernet_device(&ipgre_tap_net_ops); 1784e3d0328cSWilliam Tu pnet_tap_failed: 1785c2892f02SAlexey Dobriyan unregister_pernet_device(&ipgre_net_ops); 1786c5441932SPravin B Shelar return err; 17871da177e4SLinus Torvalds } 17881da177e4SLinus Torvalds 1789db44575fSAlexey Kuznetsov static void __exit ipgre_fini(void) 17901da177e4SLinus Torvalds { 1791e1a80002SHerbert Xu rtnl_link_unregister(&ipgre_tap_ops); 1792c19e654dSHerbert Xu rtnl_link_unregister(&ipgre_link_ops); 179384e54fe0SWilliam Tu rtnl_link_unregister(&erspan_link_ops); 17949f57c67cSPravin B Shelar gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO); 1795c5441932SPravin B Shelar unregister_pernet_device(&ipgre_tap_net_ops); 1796c2892f02SAlexey Dobriyan unregister_pernet_device(&ipgre_net_ops); 179784e54fe0SWilliam Tu unregister_pernet_device(&erspan_net_ops); 17981da177e4SLinus Torvalds } 17991da177e4SLinus Torvalds 18001da177e4SLinus Torvalds module_init(ipgre_init); 18011da177e4SLinus Torvalds module_exit(ipgre_fini); 18021da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 18034d74f8baSPatrick McHardy MODULE_ALIAS_RTNL_LINK("gre"); 18044d74f8baSPatrick McHardy MODULE_ALIAS_RTNL_LINK("gretap"); 180584e54fe0SWilliam Tu MODULE_ALIAS_RTNL_LINK("erspan"); 18068909c9adSVasiliy Kulikov MODULE_ALIAS_NETDEV("gre0"); 1807c5441932SPravin B Shelar MODULE_ALIAS_NETDEV("gretap0"); 180884e54fe0SWilliam Tu MODULE_ALIAS_NETDEV("erspan0"); 1809