11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Linux NET3: GRE over IP protocol decoder. 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Authors: Alexey Kuznetsov (kuznet@ms2.inr.ac.ru) 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or 71da177e4SLinus Torvalds * modify it under the terms of the GNU General Public License 81da177e4SLinus Torvalds * as published by the Free Software Foundation; either version 91da177e4SLinus Torvalds * 2 of the License, or (at your option) any later version. 101da177e4SLinus Torvalds * 111da177e4SLinus Torvalds */ 121da177e4SLinus Torvalds 13afd46503SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 14afd46503SJoe Perches 154fc268d2SRandy Dunlap #include <linux/capability.h> 161da177e4SLinus Torvalds #include <linux/module.h> 171da177e4SLinus Torvalds #include <linux/types.h> 181da177e4SLinus Torvalds #include <linux/kernel.h> 195a0e3ad6STejun Heo #include <linux/slab.h> 201da177e4SLinus Torvalds #include <asm/uaccess.h> 211da177e4SLinus Torvalds #include <linux/skbuff.h> 221da177e4SLinus Torvalds #include <linux/netdevice.h> 231da177e4SLinus Torvalds #include <linux/in.h> 241da177e4SLinus Torvalds #include <linux/tcp.h> 251da177e4SLinus Torvalds #include <linux/udp.h> 261da177e4SLinus Torvalds #include <linux/if_arp.h> 271da177e4SLinus Torvalds #include <linux/mroute.h> 282e15ea39SPravin B Shelar #include <linux/if_vlan.h> 291da177e4SLinus Torvalds #include <linux/init.h> 301da177e4SLinus Torvalds #include <linux/in6.h> 311da177e4SLinus Torvalds #include <linux/inetdevice.h> 321da177e4SLinus Torvalds #include <linux/igmp.h> 331da177e4SLinus Torvalds #include <linux/netfilter_ipv4.h> 34e1a80002SHerbert Xu #include <linux/etherdevice.h> 3546f25dffSKris Katterjohn #include <linux/if_ether.h> 361da177e4SLinus Torvalds 371da177e4SLinus Torvalds #include <net/sock.h> 381da177e4SLinus Torvalds #include <net/ip.h> 391da177e4SLinus Torvalds #include <net/icmp.h> 401da177e4SLinus Torvalds #include <net/protocol.h> 41c5441932SPravin B Shelar #include <net/ip_tunnels.h> 421da177e4SLinus Torvalds #include <net/arp.h> 431da177e4SLinus Torvalds #include <net/checksum.h> 441da177e4SLinus Torvalds #include <net/dsfield.h> 451da177e4SLinus Torvalds #include <net/inet_ecn.h> 461da177e4SLinus Torvalds #include <net/xfrm.h> 4759a4c759SPavel Emelyanov #include <net/net_namespace.h> 4859a4c759SPavel Emelyanov #include <net/netns/generic.h> 49c19e654dSHerbert Xu #include <net/rtnetlink.h> 5000959adeSDmitry Kozlov #include <net/gre.h> 512e15ea39SPravin B Shelar #include <net/dst_metadata.h> 521da177e4SLinus Torvalds 53dfd56b8bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6) 541da177e4SLinus Torvalds #include <net/ipv6.h> 551da177e4SLinus Torvalds #include <net/ip6_fib.h> 561da177e4SLinus Torvalds #include <net/ip6_route.h> 571da177e4SLinus Torvalds #endif 581da177e4SLinus Torvalds 591da177e4SLinus Torvalds /* 601da177e4SLinus Torvalds Problems & solutions 611da177e4SLinus Torvalds -------------------- 621da177e4SLinus Torvalds 631da177e4SLinus Torvalds 1. The most important issue is detecting local dead loops. 641da177e4SLinus Torvalds They would cause complete host lockup in transmit, which 651da177e4SLinus Torvalds would be "resolved" by stack overflow or, if queueing is enabled, 661da177e4SLinus Torvalds with infinite looping in net_bh. 671da177e4SLinus Torvalds 681da177e4SLinus Torvalds We cannot track such dead loops during route installation, 691da177e4SLinus Torvalds it is infeasible task. The most general solutions would be 701da177e4SLinus Torvalds to keep skb->encapsulation counter (sort of local ttl), 716d0722a2SEric Dumazet and silently drop packet when it expires. It is a good 72bff52857Sstephen hemminger solution, but it supposes maintaining new variable in ALL 731da177e4SLinus Torvalds skb, even if no tunneling is used. 741da177e4SLinus Torvalds 756d0722a2SEric Dumazet Current solution: xmit_recursion breaks dead loops. This is a percpu 766d0722a2SEric Dumazet counter, since when we enter the first ndo_xmit(), cpu migration is 776d0722a2SEric Dumazet forbidden. We force an exit if this counter reaches RECURSION_LIMIT 781da177e4SLinus Torvalds 791da177e4SLinus Torvalds 2. Networking dead loops would not kill routers, but would really 801da177e4SLinus Torvalds kill network. IP hop limit plays role of "t->recursion" in this case, 811da177e4SLinus Torvalds if we copy it from packet being encapsulated to upper header. 821da177e4SLinus Torvalds It is very good solution, but it introduces two problems: 831da177e4SLinus Torvalds 841da177e4SLinus Torvalds - Routing protocols, using packets with ttl=1 (OSPF, RIP2), 851da177e4SLinus Torvalds do not work over tunnels. 861da177e4SLinus Torvalds - traceroute does not work. I planned to relay ICMP from tunnel, 871da177e4SLinus Torvalds so that this problem would be solved and traceroute output 881da177e4SLinus Torvalds would even more informative. This idea appeared to be wrong: 891da177e4SLinus Torvalds only Linux complies to rfc1812 now (yes, guys, Linux is the only 901da177e4SLinus Torvalds true router now :-)), all routers (at least, in neighbourhood of mine) 911da177e4SLinus Torvalds return only 8 bytes of payload. It is the end. 921da177e4SLinus Torvalds 931da177e4SLinus Torvalds Hence, if we want that OSPF worked or traceroute said something reasonable, 941da177e4SLinus Torvalds we should search for another solution. 951da177e4SLinus Torvalds 961da177e4SLinus Torvalds One of them is to parse packet trying to detect inner encapsulation 971da177e4SLinus Torvalds made by our node. It is difficult or even impossible, especially, 98bff52857Sstephen hemminger taking into account fragmentation. TO be short, ttl is not solution at all. 991da177e4SLinus Torvalds 1001da177e4SLinus Torvalds Current solution: The solution was UNEXPECTEDLY SIMPLE. 1011da177e4SLinus Torvalds We force DF flag on tunnels with preconfigured hop limit, 1021da177e4SLinus Torvalds that is ALL. :-) Well, it does not remove the problem completely, 1031da177e4SLinus Torvalds but exponential growth of network traffic is changed to linear 1041da177e4SLinus Torvalds (branches, that exceed pmtu are pruned) and tunnel mtu 105bff52857Sstephen hemminger rapidly degrades to value <68, where looping stops. 1061da177e4SLinus Torvalds Yes, it is not good if there exists a router in the loop, 1071da177e4SLinus Torvalds which does not force DF, even when encapsulating packets have DF set. 1081da177e4SLinus Torvalds But it is not our problem! Nobody could accuse us, we made 1091da177e4SLinus Torvalds all that we could make. Even if it is your gated who injected 1101da177e4SLinus Torvalds fatal route to network, even if it were you who configured 1111da177e4SLinus Torvalds fatal static route: you are innocent. :-) 1121da177e4SLinus Torvalds 1131da177e4SLinus Torvalds Alexey Kuznetsov. 1141da177e4SLinus Torvalds */ 1151da177e4SLinus Torvalds 116eccc1bb8Sstephen hemminger static bool log_ecn_error = true; 117eccc1bb8Sstephen hemminger module_param(log_ecn_error, bool, 0644); 118eccc1bb8Sstephen hemminger MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN"); 119eccc1bb8Sstephen hemminger 120c19e654dSHerbert Xu static struct rtnl_link_ops ipgre_link_ops __read_mostly; 1211da177e4SLinus Torvalds static int ipgre_tunnel_init(struct net_device *dev); 122eb8ce741SPavel Emelyanov 123f99189b1SEric Dumazet static int ipgre_net_id __read_mostly; 124c5441932SPravin B Shelar static int gre_tap_net_id __read_mostly; 125eb8ce741SPavel Emelyanov 1269f57c67cSPravin B Shelar static int ip_gre_calc_hlen(__be16 o_flags) 1279f57c67cSPravin B Shelar { 1289f57c67cSPravin B Shelar int addend = 4; 1299f57c67cSPravin B Shelar 1309f57c67cSPravin B Shelar if (o_flags & TUNNEL_CSUM) 1319f57c67cSPravin B Shelar addend += 4; 1329f57c67cSPravin B Shelar if (o_flags & TUNNEL_KEY) 1339f57c67cSPravin B Shelar addend += 4; 1349f57c67cSPravin B Shelar if (o_flags & TUNNEL_SEQ) 1359f57c67cSPravin B Shelar addend += 4; 1369f57c67cSPravin B Shelar return addend; 1379f57c67cSPravin B Shelar } 1389f57c67cSPravin B Shelar 1399f57c67cSPravin B Shelar static __be16 gre_flags_to_tnl_flags(__be16 flags) 1409f57c67cSPravin B Shelar { 1419f57c67cSPravin B Shelar __be16 tflags = 0; 1429f57c67cSPravin B Shelar 1439f57c67cSPravin B Shelar if (flags & GRE_CSUM) 1449f57c67cSPravin B Shelar tflags |= TUNNEL_CSUM; 1459f57c67cSPravin B Shelar if (flags & GRE_ROUTING) 1469f57c67cSPravin B Shelar tflags |= TUNNEL_ROUTING; 1479f57c67cSPravin B Shelar if (flags & GRE_KEY) 1489f57c67cSPravin B Shelar tflags |= TUNNEL_KEY; 1499f57c67cSPravin B Shelar if (flags & GRE_SEQ) 1509f57c67cSPravin B Shelar tflags |= TUNNEL_SEQ; 1519f57c67cSPravin B Shelar if (flags & GRE_STRICT) 1529f57c67cSPravin B Shelar tflags |= TUNNEL_STRICT; 1539f57c67cSPravin B Shelar if (flags & GRE_REC) 1549f57c67cSPravin B Shelar tflags |= TUNNEL_REC; 1559f57c67cSPravin B Shelar if (flags & GRE_VERSION) 1569f57c67cSPravin B Shelar tflags |= TUNNEL_VERSION; 1579f57c67cSPravin B Shelar 1589f57c67cSPravin B Shelar return tflags; 1599f57c67cSPravin B Shelar } 1609f57c67cSPravin B Shelar 1619f57c67cSPravin B Shelar static __be16 tnl_flags_to_gre_flags(__be16 tflags) 1629f57c67cSPravin B Shelar { 1639f57c67cSPravin B Shelar __be16 flags = 0; 1649f57c67cSPravin B Shelar 1659f57c67cSPravin B Shelar if (tflags & TUNNEL_CSUM) 1669f57c67cSPravin B Shelar flags |= GRE_CSUM; 1679f57c67cSPravin B Shelar if (tflags & TUNNEL_ROUTING) 1689f57c67cSPravin B Shelar flags |= GRE_ROUTING; 1699f57c67cSPravin B Shelar if (tflags & TUNNEL_KEY) 1709f57c67cSPravin B Shelar flags |= GRE_KEY; 1719f57c67cSPravin B Shelar if (tflags & TUNNEL_SEQ) 1729f57c67cSPravin B Shelar flags |= GRE_SEQ; 1739f57c67cSPravin B Shelar if (tflags & TUNNEL_STRICT) 1749f57c67cSPravin B Shelar flags |= GRE_STRICT; 1759f57c67cSPravin B Shelar if (tflags & TUNNEL_REC) 1769f57c67cSPravin B Shelar flags |= GRE_REC; 1779f57c67cSPravin B Shelar if (tflags & TUNNEL_VERSION) 1789f57c67cSPravin B Shelar flags |= GRE_VERSION; 1799f57c67cSPravin B Shelar 1809f57c67cSPravin B Shelar return flags; 1819f57c67cSPravin B Shelar } 1829f57c67cSPravin B Shelar 1839f57c67cSPravin B Shelar static int parse_gre_header(struct sk_buff *skb, struct tnl_ptk_info *tpi, 1849f57c67cSPravin B Shelar bool *csum_err) 1859f57c67cSPravin B Shelar { 1869f57c67cSPravin B Shelar const struct gre_base_hdr *greh; 1879f57c67cSPravin B Shelar __be32 *options; 1889f57c67cSPravin B Shelar int hdr_len; 1899f57c67cSPravin B Shelar 1909f57c67cSPravin B Shelar if (unlikely(!pskb_may_pull(skb, sizeof(struct gre_base_hdr)))) 1919f57c67cSPravin B Shelar return -EINVAL; 1929f57c67cSPravin B Shelar 1939f57c67cSPravin B Shelar greh = (struct gre_base_hdr *)skb_transport_header(skb); 1949f57c67cSPravin B Shelar if (unlikely(greh->flags & (GRE_VERSION | GRE_ROUTING))) 1959f57c67cSPravin B Shelar return -EINVAL; 1969f57c67cSPravin B Shelar 1979f57c67cSPravin B Shelar tpi->flags = gre_flags_to_tnl_flags(greh->flags); 1989f57c67cSPravin B Shelar hdr_len = ip_gre_calc_hlen(tpi->flags); 1999f57c67cSPravin B Shelar 2009f57c67cSPravin B Shelar if (!pskb_may_pull(skb, hdr_len)) 2019f57c67cSPravin B Shelar return -EINVAL; 2029f57c67cSPravin B Shelar 2039f57c67cSPravin B Shelar greh = (struct gre_base_hdr *)skb_transport_header(skb); 2049f57c67cSPravin B Shelar tpi->proto = greh->protocol; 2059f57c67cSPravin B Shelar 2069f57c67cSPravin B Shelar options = (__be32 *)(greh + 1); 2079f57c67cSPravin B Shelar if (greh->flags & GRE_CSUM) { 2089f57c67cSPravin B Shelar if (skb_checksum_simple_validate(skb)) { 2099f57c67cSPravin B Shelar *csum_err = true; 2109f57c67cSPravin B Shelar return -EINVAL; 2119f57c67cSPravin B Shelar } 2129f57c67cSPravin B Shelar 2139f57c67cSPravin B Shelar skb_checksum_try_convert(skb, IPPROTO_GRE, 0, 2149f57c67cSPravin B Shelar null_compute_pseudo); 2159f57c67cSPravin B Shelar options++; 2169f57c67cSPravin B Shelar } 2179f57c67cSPravin B Shelar 2189f57c67cSPravin B Shelar if (greh->flags & GRE_KEY) { 2199f57c67cSPravin B Shelar tpi->key = *options; 2209f57c67cSPravin B Shelar options++; 2219f57c67cSPravin B Shelar } else { 2229f57c67cSPravin B Shelar tpi->key = 0; 2239f57c67cSPravin B Shelar } 2249f57c67cSPravin B Shelar if (unlikely(greh->flags & GRE_SEQ)) { 2259f57c67cSPravin B Shelar tpi->seq = *options; 2269f57c67cSPravin B Shelar options++; 2279f57c67cSPravin B Shelar } else { 2289f57c67cSPravin B Shelar tpi->seq = 0; 2299f57c67cSPravin B Shelar } 2309f57c67cSPravin B Shelar /* WCCP version 1 and 2 protocol decoding. 2319f57c67cSPravin B Shelar * - Change protocol to IP 2329f57c67cSPravin B Shelar * - When dealing with WCCPv2, Skip extra 4 bytes in GRE header 2339f57c67cSPravin B Shelar */ 2349f57c67cSPravin B Shelar if (greh->flags == 0 && tpi->proto == htons(ETH_P_WCCP)) { 2359f57c67cSPravin B Shelar tpi->proto = htons(ETH_P_IP); 2369f57c67cSPravin B Shelar if ((*(u8 *)options & 0xF0) != 0x40) { 2379f57c67cSPravin B Shelar hdr_len += 4; 2389f57c67cSPravin B Shelar if (!pskb_may_pull(skb, hdr_len)) 2399f57c67cSPravin B Shelar return -EINVAL; 2409f57c67cSPravin B Shelar } 2419f57c67cSPravin B Shelar } 2429f57c67cSPravin B Shelar return iptunnel_pull_header(skb, hdr_len, tpi->proto); 2439f57c67cSPravin B Shelar } 2449f57c67cSPravin B Shelar 2459f57c67cSPravin B Shelar static void ipgre_err(struct sk_buff *skb, u32 info, 246bda7bb46SPravin B Shelar const struct tnl_ptk_info *tpi) 2471da177e4SLinus Torvalds { 2481da177e4SLinus Torvalds 249071f92d0SRami Rosen /* All the routers (except for Linux) return only 2501da177e4SLinus Torvalds 8 bytes of packet payload. It means, that precise relaying of 2511da177e4SLinus Torvalds ICMP in the real Internet is absolutely infeasible. 2521da177e4SLinus Torvalds 2531da177e4SLinus Torvalds Moreover, Cisco "wise men" put GRE key to the third word 254c5441932SPravin B Shelar in GRE header. It makes impossible maintaining even soft 255c5441932SPravin B Shelar state for keyed GRE tunnels with enabled checksum. Tell 256c5441932SPravin B Shelar them "thank you". 2571da177e4SLinus Torvalds 2581da177e4SLinus Torvalds Well, I wonder, rfc1812 was written by Cisco employee, 259bff52857Sstephen hemminger what the hell these idiots break standards established 260bff52857Sstephen hemminger by themselves??? 2611da177e4SLinus Torvalds */ 262c5441932SPravin B Shelar struct net *net = dev_net(skb->dev); 263c5441932SPravin B Shelar struct ip_tunnel_net *itn; 26496f5a846SEric Dumazet const struct iphdr *iph; 26588c7664fSArnaldo Carvalho de Melo const int type = icmp_hdr(skb)->type; 26688c7664fSArnaldo Carvalho de Melo const int code = icmp_hdr(skb)->code; 2671da177e4SLinus Torvalds struct ip_tunnel *t; 268d2083287Sstephen hemminger 2691da177e4SLinus Torvalds switch (type) { 2701da177e4SLinus Torvalds default: 2711da177e4SLinus Torvalds case ICMP_PARAMETERPROB: 2729f57c67cSPravin B Shelar return; 2731da177e4SLinus Torvalds 2741da177e4SLinus Torvalds case ICMP_DEST_UNREACH: 2751da177e4SLinus Torvalds switch (code) { 2761da177e4SLinus Torvalds case ICMP_SR_FAILED: 2771da177e4SLinus Torvalds case ICMP_PORT_UNREACH: 2781da177e4SLinus Torvalds /* Impossible event. */ 2799f57c67cSPravin B Shelar return; 2801da177e4SLinus Torvalds default: 2811da177e4SLinus Torvalds /* All others are translated to HOST_UNREACH. 2821da177e4SLinus Torvalds rfc2003 contains "deep thoughts" about NET_UNREACH, 2831da177e4SLinus Torvalds I believe they are just ether pollution. --ANK 2841da177e4SLinus Torvalds */ 2851da177e4SLinus Torvalds break; 2861da177e4SLinus Torvalds } 2871da177e4SLinus Torvalds break; 2889f57c67cSPravin B Shelar 2891da177e4SLinus Torvalds case ICMP_TIME_EXCEEDED: 2901da177e4SLinus Torvalds if (code != ICMP_EXC_TTL) 2919f57c67cSPravin B Shelar return; 2921da177e4SLinus Torvalds break; 29355be7a9cSDavid S. Miller 29455be7a9cSDavid S. Miller case ICMP_REDIRECT: 29555be7a9cSDavid S. Miller break; 2961da177e4SLinus Torvalds } 2971da177e4SLinus Torvalds 298bda7bb46SPravin B Shelar if (tpi->proto == htons(ETH_P_TEB)) 299c5441932SPravin B Shelar itn = net_generic(net, gre_tap_net_id); 300c5441932SPravin B Shelar else 301c5441932SPravin B Shelar itn = net_generic(net, ipgre_net_id); 302c5441932SPravin B Shelar 303c0c0c50fSDuan Jiong iph = (const struct iphdr *)(icmp_hdr(skb) + 1); 304bda7bb46SPravin B Shelar t = ip_tunnel_lookup(itn, skb->dev->ifindex, tpi->flags, 305bda7bb46SPravin B Shelar iph->daddr, iph->saddr, tpi->key); 306d2083287Sstephen hemminger 30751456b29SIan Morris if (!t) 3089f57c67cSPravin B Shelar return; 30936393395SDavid S. Miller 31036393395SDavid S. Miller if (t->parms.iph.daddr == 0 || 311f97c1e0cSJoe Perches ipv4_is_multicast(t->parms.iph.daddr)) 3129f57c67cSPravin B Shelar return; 3131da177e4SLinus Torvalds 3141da177e4SLinus Torvalds if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED) 3159f57c67cSPravin B Shelar return; 3161da177e4SLinus Torvalds 317da6185d8SWei Yongjun if (time_before(jiffies, t->err_time + IPTUNNEL_ERR_TIMEO)) 3181da177e4SLinus Torvalds t->err_count++; 3191da177e4SLinus Torvalds else 3201da177e4SLinus Torvalds t->err_count = 1; 3211da177e4SLinus Torvalds t->err_time = jiffies; 3229f57c67cSPravin B Shelar } 3239f57c67cSPravin B Shelar 3249f57c67cSPravin B Shelar static void gre_err(struct sk_buff *skb, u32 info) 3259f57c67cSPravin B Shelar { 3269f57c67cSPravin B Shelar /* All the routers (except for Linux) return only 3279f57c67cSPravin B Shelar * 8 bytes of packet payload. It means, that precise relaying of 3289f57c67cSPravin B Shelar * ICMP in the real Internet is absolutely infeasible. 3299f57c67cSPravin B Shelar * 3309f57c67cSPravin B Shelar * Moreover, Cisco "wise men" put GRE key to the third word 3319f57c67cSPravin B Shelar * in GRE header. It makes impossible maintaining even soft 3329f57c67cSPravin B Shelar * state for keyed 3339f57c67cSPravin B Shelar * GRE tunnels with enabled checksum. Tell them "thank you". 3349f57c67cSPravin B Shelar * 3359f57c67cSPravin B Shelar * Well, I wonder, rfc1812 was written by Cisco employee, 3369f57c67cSPravin B Shelar * what the hell these idiots break standards established 3379f57c67cSPravin B Shelar * by themselves??? 3389f57c67cSPravin B Shelar */ 3399f57c67cSPravin B Shelar 3409f57c67cSPravin B Shelar const int type = icmp_hdr(skb)->type; 3419f57c67cSPravin B Shelar const int code = icmp_hdr(skb)->code; 3429f57c67cSPravin B Shelar struct tnl_ptk_info tpi; 3439f57c67cSPravin B Shelar bool csum_err = false; 3449f57c67cSPravin B Shelar 3459f57c67cSPravin B Shelar if (parse_gre_header(skb, &tpi, &csum_err)) { 3469f57c67cSPravin B Shelar if (!csum_err) /* ignore csum errors. */ 3479f57c67cSPravin B Shelar return; 3489f57c67cSPravin B Shelar } 3499f57c67cSPravin B Shelar 3509f57c67cSPravin B Shelar if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) { 3519f57c67cSPravin B Shelar ipv4_update_pmtu(skb, dev_net(skb->dev), info, 3529f57c67cSPravin B Shelar skb->dev->ifindex, 0, IPPROTO_GRE, 0); 3539f57c67cSPravin B Shelar return; 3549f57c67cSPravin B Shelar } 3559f57c67cSPravin B Shelar if (type == ICMP_REDIRECT) { 3569f57c67cSPravin B Shelar ipv4_redirect(skb, dev_net(skb->dev), skb->dev->ifindex, 0, 3579f57c67cSPravin B Shelar IPPROTO_GRE, 0); 3589f57c67cSPravin B Shelar return; 3599f57c67cSPravin B Shelar } 3609f57c67cSPravin B Shelar 3619f57c67cSPravin B Shelar ipgre_err(skb, info, &tpi); 3621da177e4SLinus Torvalds } 3631da177e4SLinus Torvalds 3642e15ea39SPravin B Shelar static __be64 key_to_tunnel_id(__be32 key) 3652e15ea39SPravin B Shelar { 3662e15ea39SPravin B Shelar #ifdef __BIG_ENDIAN 3672e15ea39SPravin B Shelar return (__force __be64)((__force u32)key); 3682e15ea39SPravin B Shelar #else 3692e15ea39SPravin B Shelar return (__force __be64)((__force u64)key << 32); 3702e15ea39SPravin B Shelar #endif 3712e15ea39SPravin B Shelar } 3722e15ea39SPravin B Shelar 3732e15ea39SPravin B Shelar /* Returns the least-significant 32 bits of a __be64. */ 3742e15ea39SPravin B Shelar static __be32 tunnel_id_to_key(__be64 x) 3752e15ea39SPravin B Shelar { 3762e15ea39SPravin B Shelar #ifdef __BIG_ENDIAN 3772e15ea39SPravin B Shelar return (__force __be32)x; 3782e15ea39SPravin B Shelar #else 3792e15ea39SPravin B Shelar return (__force __be32)((__force u64)x >> 32); 3802e15ea39SPravin B Shelar #endif 3812e15ea39SPravin B Shelar } 3822e15ea39SPravin B Shelar 383bda7bb46SPravin B Shelar static int ipgre_rcv(struct sk_buff *skb, const struct tnl_ptk_info *tpi) 3841da177e4SLinus Torvalds { 385c5441932SPravin B Shelar struct net *net = dev_net(skb->dev); 3862e15ea39SPravin B Shelar struct metadata_dst *tun_dst = NULL; 387c5441932SPravin B Shelar struct ip_tunnel_net *itn; 388b71d1d42SEric Dumazet const struct iphdr *iph; 3891da177e4SLinus Torvalds struct ip_tunnel *tunnel; 3901da177e4SLinus Torvalds 391bda7bb46SPravin B Shelar if (tpi->proto == htons(ETH_P_TEB)) 392c5441932SPravin B Shelar itn = net_generic(net, gre_tap_net_id); 393c5441932SPravin B Shelar else 394c5441932SPravin B Shelar itn = net_generic(net, ipgre_net_id); 395c5441932SPravin B Shelar 396eddc9ec5SArnaldo Carvalho de Melo iph = ip_hdr(skb); 397bda7bb46SPravin B Shelar tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, tpi->flags, 398bda7bb46SPravin B Shelar iph->saddr, iph->daddr, tpi->key); 3991da177e4SLinus Torvalds 400d2083287Sstephen hemminger if (tunnel) { 4010e3da5bbSTimo Teräs skb_pop_mac_header(skb); 4022e15ea39SPravin B Shelar if (tunnel->collect_md) { 403*c29a70d2SPravin B Shelar __be16 flags; 404*c29a70d2SPravin B Shelar __be64 tun_id; 4052e15ea39SPravin B Shelar 406*c29a70d2SPravin B Shelar flags = tpi->flags & (TUNNEL_CSUM | TUNNEL_KEY); 407*c29a70d2SPravin B Shelar tun_id = key_to_tunnel_id(tpi->key); 408*c29a70d2SPravin B Shelar tun_dst = ip_tun_rx_dst(skb, flags, tun_id, 0); 4092e15ea39SPravin B Shelar if (!tun_dst) 4102e15ea39SPravin B Shelar return PACKET_REJECT; 4112e15ea39SPravin B Shelar } 4122e15ea39SPravin B Shelar 4132e15ea39SPravin B Shelar ip_tunnel_rcv(tunnel, skb, tpi, tun_dst, log_ecn_error); 414bda7bb46SPravin B Shelar return PACKET_RCVD; 4151da177e4SLinus Torvalds } 416bda7bb46SPravin B Shelar return PACKET_REJECT; 4171da177e4SLinus Torvalds } 4181da177e4SLinus Torvalds 4199f57c67cSPravin B Shelar static int gre_rcv(struct sk_buff *skb) 4209f57c67cSPravin B Shelar { 4219f57c67cSPravin B Shelar struct tnl_ptk_info tpi; 4229f57c67cSPravin B Shelar bool csum_err = false; 4239f57c67cSPravin B Shelar 4249f57c67cSPravin B Shelar #ifdef CONFIG_NET_IPGRE_BROADCAST 4259f57c67cSPravin B Shelar if (ipv4_is_multicast(ip_hdr(skb)->daddr)) { 4269f57c67cSPravin B Shelar /* Looped back packet, drop it! */ 4279f57c67cSPravin B Shelar if (rt_is_output_route(skb_rtable(skb))) 4289f57c67cSPravin B Shelar goto drop; 4299f57c67cSPravin B Shelar } 4309f57c67cSPravin B Shelar #endif 4319f57c67cSPravin B Shelar 4329f57c67cSPravin B Shelar if (parse_gre_header(skb, &tpi, &csum_err) < 0) 4339f57c67cSPravin B Shelar goto drop; 4349f57c67cSPravin B Shelar 4359f57c67cSPravin B Shelar if (ipgre_rcv(skb, &tpi) == PACKET_RCVD) 4369f57c67cSPravin B Shelar return 0; 4379f57c67cSPravin B Shelar 4389f57c67cSPravin B Shelar icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); 4399f57c67cSPravin B Shelar drop: 4409f57c67cSPravin B Shelar kfree_skb(skb); 4419f57c67cSPravin B Shelar return 0; 4429f57c67cSPravin B Shelar } 4439f57c67cSPravin B Shelar 4442e15ea39SPravin B Shelar static void build_header(struct sk_buff *skb, int hdr_len, __be16 flags, 4452e15ea39SPravin B Shelar __be16 proto, __be32 key, __be32 seq) 4462e15ea39SPravin B Shelar { 4472e15ea39SPravin B Shelar struct gre_base_hdr *greh; 4482e15ea39SPravin B Shelar 4492e15ea39SPravin B Shelar skb_push(skb, hdr_len); 4502e15ea39SPravin B Shelar 4512e15ea39SPravin B Shelar skb_reset_transport_header(skb); 4522e15ea39SPravin B Shelar greh = (struct gre_base_hdr *)skb->data; 4532e15ea39SPravin B Shelar greh->flags = tnl_flags_to_gre_flags(flags); 4542e15ea39SPravin B Shelar greh->protocol = proto; 4552e15ea39SPravin B Shelar 4562e15ea39SPravin B Shelar if (flags & (TUNNEL_KEY | TUNNEL_CSUM | TUNNEL_SEQ)) { 4572e15ea39SPravin B Shelar __be32 *ptr = (__be32 *)(((u8 *)greh) + hdr_len - 4); 4582e15ea39SPravin B Shelar 4592e15ea39SPravin B Shelar if (flags & TUNNEL_SEQ) { 4602e15ea39SPravin B Shelar *ptr = seq; 4612e15ea39SPravin B Shelar ptr--; 4622e15ea39SPravin B Shelar } 4632e15ea39SPravin B Shelar if (flags & TUNNEL_KEY) { 4642e15ea39SPravin B Shelar *ptr = key; 4652e15ea39SPravin B Shelar ptr--; 4662e15ea39SPravin B Shelar } 4672e15ea39SPravin B Shelar if (flags & TUNNEL_CSUM && 4682e15ea39SPravin B Shelar !(skb_shinfo(skb)->gso_type & 4692e15ea39SPravin B Shelar (SKB_GSO_GRE | SKB_GSO_GRE_CSUM))) { 4702e15ea39SPravin B Shelar *ptr = 0; 4712e15ea39SPravin B Shelar *(__sum16 *)ptr = csum_fold(skb_checksum(skb, 0, 4722e15ea39SPravin B Shelar skb->len, 0)); 4732e15ea39SPravin B Shelar } 4742e15ea39SPravin B Shelar } 4752e15ea39SPravin B Shelar } 4762e15ea39SPravin B Shelar 477c5441932SPravin B Shelar static void __gre_xmit(struct sk_buff *skb, struct net_device *dev, 478c5441932SPravin B Shelar const struct iphdr *tnl_params, 479c5441932SPravin B Shelar __be16 proto) 480c5441932SPravin B Shelar { 481c5441932SPravin B Shelar struct ip_tunnel *tunnel = netdev_priv(dev); 482c5441932SPravin B Shelar 483c5441932SPravin B Shelar if (tunnel->parms.o_flags & TUNNEL_SEQ) 484c5441932SPravin B Shelar tunnel->o_seqno++; 485cef401deSEric Dumazet 486c5441932SPravin B Shelar /* Push GRE header. */ 4872e15ea39SPravin B Shelar build_header(skb, tunnel->tun_hlen, tunnel->parms.o_flags, 4882e15ea39SPravin B Shelar proto, tunnel->parms.o_key, htonl(tunnel->o_seqno)); 4891da177e4SLinus Torvalds 4902e15ea39SPravin B Shelar skb_set_inner_protocol(skb, proto); 491bf3d6a8fSNicolas Dichtel ip_tunnel_xmit(skb, dev, tnl_params, tnl_params->protocol); 4921da177e4SLinus Torvalds } 4931da177e4SLinus Torvalds 494b2acd1dcSPravin B Shelar static struct sk_buff *gre_handle_offloads(struct sk_buff *skb, 495b2acd1dcSPravin B Shelar bool csum) 496b2acd1dcSPravin B Shelar { 497b2acd1dcSPravin B Shelar return iptunnel_handle_offloads(skb, csum, 498b2acd1dcSPravin B Shelar csum ? SKB_GSO_GRE_CSUM : SKB_GSO_GRE); 499b2acd1dcSPravin B Shelar } 500b2acd1dcSPravin B Shelar 5012e15ea39SPravin B Shelar static void gre_fb_xmit(struct sk_buff *skb, struct net_device *dev) 5022e15ea39SPravin B Shelar { 5032e15ea39SPravin B Shelar struct ip_tunnel_info *tun_info; 5042e15ea39SPravin B Shelar struct net *net = dev_net(dev); 5052e15ea39SPravin B Shelar const struct ip_tunnel_key *key; 5062e15ea39SPravin B Shelar struct flowi4 fl; 5072e15ea39SPravin B Shelar struct rtable *rt; 5082e15ea39SPravin B Shelar int min_headroom; 5092e15ea39SPravin B Shelar int tunnel_hlen; 5102e15ea39SPravin B Shelar __be16 df, flags; 5112e15ea39SPravin B Shelar int err; 5122e15ea39SPravin B Shelar 51361adedf3SJiri Benc tun_info = skb_tunnel_info(skb); 5142e15ea39SPravin B Shelar if (unlikely(!tun_info || tun_info->mode != IP_TUNNEL_INFO_TX)) 5152e15ea39SPravin B Shelar goto err_free_skb; 5162e15ea39SPravin B Shelar 5172e15ea39SPravin B Shelar key = &tun_info->key; 5182e15ea39SPravin B Shelar memset(&fl, 0, sizeof(fl)); 519c1ea5d67SJiri Benc fl.daddr = key->u.ipv4.dst; 520c1ea5d67SJiri Benc fl.saddr = key->u.ipv4.src; 5217c383fb2SJiri Benc fl.flowi4_tos = RT_TOS(key->tos); 5222e15ea39SPravin B Shelar fl.flowi4_mark = skb->mark; 5232e15ea39SPravin B Shelar fl.flowi4_proto = IPPROTO_GRE; 5242e15ea39SPravin B Shelar 5252e15ea39SPravin B Shelar rt = ip_route_output_key(net, &fl); 5262e15ea39SPravin B Shelar if (IS_ERR(rt)) 5272e15ea39SPravin B Shelar goto err_free_skb; 5282e15ea39SPravin B Shelar 5292e15ea39SPravin B Shelar tunnel_hlen = ip_gre_calc_hlen(key->tun_flags); 5302e15ea39SPravin B Shelar 5312e15ea39SPravin B Shelar min_headroom = LL_RESERVED_SPACE(rt->dst.dev) + rt->dst.header_len 5322e15ea39SPravin B Shelar + tunnel_hlen + sizeof(struct iphdr); 5332e15ea39SPravin B Shelar if (skb_headroom(skb) < min_headroom || skb_header_cloned(skb)) { 5342e15ea39SPravin B Shelar int head_delta = SKB_DATA_ALIGN(min_headroom - 5352e15ea39SPravin B Shelar skb_headroom(skb) + 5362e15ea39SPravin B Shelar 16); 5372e15ea39SPravin B Shelar err = pskb_expand_head(skb, max_t(int, head_delta, 0), 5382e15ea39SPravin B Shelar 0, GFP_ATOMIC); 5392e15ea39SPravin B Shelar if (unlikely(err)) 5402e15ea39SPravin B Shelar goto err_free_rt; 5412e15ea39SPravin B Shelar } 5422e15ea39SPravin B Shelar 5432e15ea39SPravin B Shelar /* Push Tunnel header. */ 5442e15ea39SPravin B Shelar skb = gre_handle_offloads(skb, !!(tun_info->key.tun_flags & TUNNEL_CSUM)); 5452e15ea39SPravin B Shelar if (IS_ERR(skb)) { 5462e15ea39SPravin B Shelar skb = NULL; 5472e15ea39SPravin B Shelar goto err_free_rt; 5482e15ea39SPravin B Shelar } 5492e15ea39SPravin B Shelar 5502e15ea39SPravin B Shelar flags = tun_info->key.tun_flags & (TUNNEL_CSUM | TUNNEL_KEY); 5512e15ea39SPravin B Shelar build_header(skb, tunnel_hlen, flags, htons(ETH_P_TEB), 5522e15ea39SPravin B Shelar tunnel_id_to_key(tun_info->key.tun_id), 0); 5532e15ea39SPravin B Shelar 5542e15ea39SPravin B Shelar df = key->tun_flags & TUNNEL_DONT_FRAGMENT ? htons(IP_DF) : 0; 5552e15ea39SPravin B Shelar err = iptunnel_xmit(skb->sk, rt, skb, fl.saddr, 556c1ea5d67SJiri Benc key->u.ipv4.dst, IPPROTO_GRE, 5577c383fb2SJiri Benc key->tos, key->ttl, df, false); 5582e15ea39SPravin B Shelar iptunnel_xmit_stats(err, &dev->stats, dev->tstats); 5592e15ea39SPravin B Shelar return; 5602e15ea39SPravin B Shelar 5612e15ea39SPravin B Shelar err_free_rt: 5622e15ea39SPravin B Shelar ip_rt_put(rt); 5632e15ea39SPravin B Shelar err_free_skb: 5642e15ea39SPravin B Shelar kfree_skb(skb); 5652e15ea39SPravin B Shelar dev->stats.tx_dropped++; 5662e15ea39SPravin B Shelar } 5672e15ea39SPravin B Shelar 568c5441932SPravin B Shelar static netdev_tx_t ipgre_xmit(struct sk_buff *skb, 569c5441932SPravin B Shelar struct net_device *dev) 570ee34c1ebSMichal Schmidt { 571c5441932SPravin B Shelar struct ip_tunnel *tunnel = netdev_priv(dev); 572c5441932SPravin B Shelar const struct iphdr *tnl_params; 573ee34c1ebSMichal Schmidt 5742e15ea39SPravin B Shelar if (tunnel->collect_md) { 5752e15ea39SPravin B Shelar gre_fb_xmit(skb, dev); 5762e15ea39SPravin B Shelar return NETDEV_TX_OK; 5772e15ea39SPravin B Shelar } 5782e15ea39SPravin B Shelar 579c5441932SPravin B Shelar if (dev->header_ops) { 580c5441932SPravin B Shelar /* Need space for new headers */ 581c5441932SPravin B Shelar if (skb_cow_head(skb, dev->needed_headroom - 5822bac7cb3SChen Gang (tunnel->hlen + sizeof(struct iphdr)))) 583c5441932SPravin B Shelar goto free_skb; 584ee34c1ebSMichal Schmidt 585c5441932SPravin B Shelar tnl_params = (const struct iphdr *)skb->data; 586cbb1e85fSDavid S. Miller 587c5441932SPravin B Shelar /* Pull skb since ip_tunnel_xmit() needs skb->data pointing 588c5441932SPravin B Shelar * to gre header. 589c5441932SPravin B Shelar */ 590c5441932SPravin B Shelar skb_pull(skb, tunnel->hlen + sizeof(struct iphdr)); 5918a0033a9STimo Teräs skb_reset_mac_header(skb); 592c5441932SPravin B Shelar } else { 593c5441932SPravin B Shelar if (skb_cow_head(skb, dev->needed_headroom)) 594c5441932SPravin B Shelar goto free_skb; 595c5441932SPravin B Shelar 596c5441932SPravin B Shelar tnl_params = &tunnel->parms.iph; 597ee34c1ebSMichal Schmidt } 598e1a80002SHerbert Xu 5998a0033a9STimo Teräs skb = gre_handle_offloads(skb, !!(tunnel->parms.o_flags&TUNNEL_CSUM)); 6008a0033a9STimo Teräs if (IS_ERR(skb)) 6018a0033a9STimo Teräs goto out; 6028a0033a9STimo Teräs 603c5441932SPravin B Shelar __gre_xmit(skb, dev, tnl_params, skb->protocol); 604c5441932SPravin B Shelar return NETDEV_TX_OK; 605c5441932SPravin B Shelar 606c5441932SPravin B Shelar free_skb: 6073acfa1e7SEric Dumazet kfree_skb(skb); 608c5441932SPravin B Shelar out: 609c5441932SPravin B Shelar dev->stats.tx_dropped++; 610c5441932SPravin B Shelar return NETDEV_TX_OK; 611ee34c1ebSMichal Schmidt } 612ee34c1ebSMichal Schmidt 613c5441932SPravin B Shelar static netdev_tx_t gre_tap_xmit(struct sk_buff *skb, 614c5441932SPravin B Shelar struct net_device *dev) 615c5441932SPravin B Shelar { 616c5441932SPravin B Shelar struct ip_tunnel *tunnel = netdev_priv(dev); 617ee34c1ebSMichal Schmidt 6182e15ea39SPravin B Shelar if (tunnel->collect_md) { 6192e15ea39SPravin B Shelar gre_fb_xmit(skb, dev); 6202e15ea39SPravin B Shelar return NETDEV_TX_OK; 6212e15ea39SPravin B Shelar } 6222e15ea39SPravin B Shelar 62345f2e997SPravin B Shelar skb = gre_handle_offloads(skb, !!(tunnel->parms.o_flags&TUNNEL_CSUM)); 624c5441932SPravin B Shelar if (IS_ERR(skb)) 625c5441932SPravin B Shelar goto out; 626ee34c1ebSMichal Schmidt 627c5441932SPravin B Shelar if (skb_cow_head(skb, dev->needed_headroom)) 628c5441932SPravin B Shelar goto free_skb; 62942aa9162SHerbert Xu 630c5441932SPravin B Shelar __gre_xmit(skb, dev, &tunnel->parms.iph, htons(ETH_P_TEB)); 631c5441932SPravin B Shelar return NETDEV_TX_OK; 632c5441932SPravin B Shelar 633c5441932SPravin B Shelar free_skb: 6343acfa1e7SEric Dumazet kfree_skb(skb); 635c5441932SPravin B Shelar out: 636c5441932SPravin B Shelar dev->stats.tx_dropped++; 637c5441932SPravin B Shelar return NETDEV_TX_OK; 63868c33163SPravin B Shelar } 639ee34c1ebSMichal Schmidt 640c5441932SPravin B Shelar static int ipgre_tunnel_ioctl(struct net_device *dev, 641c5441932SPravin B Shelar struct ifreq *ifr, int cmd) 6421da177e4SLinus Torvalds { 6434565e991STom Herbert int err; 6441da177e4SLinus Torvalds struct ip_tunnel_parm p; 6451da177e4SLinus Torvalds 6461da177e4SLinus Torvalds if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) 647c5441932SPravin B Shelar return -EFAULT; 6486c734fb8SCong Wang if (cmd == SIOCADDTUNNEL || cmd == SIOCCHGTUNNEL) { 6491da177e4SLinus Torvalds if (p.iph.version != 4 || p.iph.protocol != IPPROTO_GRE || 6501da177e4SLinus Torvalds p.iph.ihl != 5 || (p.iph.frag_off&htons(~IP_DF)) || 6516c734fb8SCong Wang ((p.i_flags|p.o_flags)&(GRE_VERSION|GRE_ROUTING))) 6521da177e4SLinus Torvalds return -EINVAL; 653c5441932SPravin B Shelar } 654c5441932SPravin B Shelar p.i_flags = gre_flags_to_tnl_flags(p.i_flags); 655c5441932SPravin B Shelar p.o_flags = gre_flags_to_tnl_flags(p.o_flags); 656c5441932SPravin B Shelar 657c5441932SPravin B Shelar err = ip_tunnel_ioctl(dev, &p, cmd); 658c5441932SPravin B Shelar if (err) 659c5441932SPravin B Shelar return err; 660c5441932SPravin B Shelar 661c5441932SPravin B Shelar p.i_flags = tnl_flags_to_gre_flags(p.i_flags); 662c5441932SPravin B Shelar p.o_flags = tnl_flags_to_gre_flags(p.o_flags); 663c5441932SPravin B Shelar 664c5441932SPravin B Shelar if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p))) 665c5441932SPravin B Shelar return -EFAULT; 6661da177e4SLinus Torvalds return 0; 6671da177e4SLinus Torvalds } 6681da177e4SLinus Torvalds 6691da177e4SLinus Torvalds /* Nice toy. Unfortunately, useless in real life :-) 6701da177e4SLinus Torvalds It allows to construct virtual multiprotocol broadcast "LAN" 6711da177e4SLinus Torvalds over the Internet, provided multicast routing is tuned. 6721da177e4SLinus Torvalds 6731da177e4SLinus Torvalds 6741da177e4SLinus Torvalds I have no idea was this bicycle invented before me, 6751da177e4SLinus Torvalds so that I had to set ARPHRD_IPGRE to a random value. 6761da177e4SLinus Torvalds I have an impression, that Cisco could make something similar, 6771da177e4SLinus Torvalds but this feature is apparently missing in IOS<=11.2(8). 6781da177e4SLinus Torvalds 6791da177e4SLinus Torvalds I set up 10.66.66/24 and fec0:6666:6666::0/96 as virtual networks 6801da177e4SLinus Torvalds with broadcast 224.66.66.66. If you have access to mbone, play with me :-) 6811da177e4SLinus Torvalds 6821da177e4SLinus Torvalds ping -t 255 224.66.66.66 6831da177e4SLinus Torvalds 6841da177e4SLinus Torvalds If nobody answers, mbone does not work. 6851da177e4SLinus Torvalds 6861da177e4SLinus Torvalds ip tunnel add Universe mode gre remote 224.66.66.66 local <Your_real_addr> ttl 255 6871da177e4SLinus Torvalds ip addr add 10.66.66.<somewhat>/24 dev Universe 6881da177e4SLinus Torvalds ifconfig Universe up 6891da177e4SLinus Torvalds ifconfig Universe add fe80::<Your_real_addr>/10 6901da177e4SLinus Torvalds ifconfig Universe add fec0:6666:6666::<Your_real_addr>/96 6911da177e4SLinus Torvalds ftp 10.66.66.66 6921da177e4SLinus Torvalds ... 6931da177e4SLinus Torvalds ftp fec0:6666:6666::193.233.7.65 6941da177e4SLinus Torvalds ... 6951da177e4SLinus Torvalds */ 6963b04dddeSStephen Hemminger static int ipgre_header(struct sk_buff *skb, struct net_device *dev, 6973b04dddeSStephen Hemminger unsigned short type, 6981507850bSEric Dumazet const void *daddr, const void *saddr, unsigned int len) 6991da177e4SLinus Torvalds { 7002941a486SPatrick McHardy struct ip_tunnel *t = netdev_priv(dev); 701c5441932SPravin B Shelar struct iphdr *iph; 702c5441932SPravin B Shelar struct gre_base_hdr *greh; 703c5441932SPravin B Shelar 704c5441932SPravin B Shelar iph = (struct iphdr *)skb_push(skb, t->hlen + sizeof(*iph)); 705c5441932SPravin B Shelar greh = (struct gre_base_hdr *)(iph+1); 706c5441932SPravin B Shelar greh->flags = tnl_flags_to_gre_flags(t->parms.o_flags); 707c5441932SPravin B Shelar greh->protocol = htons(type); 7081da177e4SLinus Torvalds 7091da177e4SLinus Torvalds memcpy(iph, &t->parms.iph, sizeof(struct iphdr)); 7101da177e4SLinus Torvalds 711c5441932SPravin B Shelar /* Set the source hardware address. */ 7121da177e4SLinus Torvalds if (saddr) 7131da177e4SLinus Torvalds memcpy(&iph->saddr, saddr, 4); 7146d55cb91STimo Teräs if (daddr) 7151da177e4SLinus Torvalds memcpy(&iph->daddr, daddr, 4); 7166d55cb91STimo Teräs if (iph->daddr) 71777a482bdSTimo Teräs return t->hlen + sizeof(*iph); 7181da177e4SLinus Torvalds 719c5441932SPravin B Shelar return -(t->hlen + sizeof(*iph)); 7201da177e4SLinus Torvalds } 7211da177e4SLinus Torvalds 7226a5f44d7STimo Teras static int ipgre_header_parse(const struct sk_buff *skb, unsigned char *haddr) 7236a5f44d7STimo Teras { 724b71d1d42SEric Dumazet const struct iphdr *iph = (const struct iphdr *) skb_mac_header(skb); 7256a5f44d7STimo Teras memcpy(haddr, &iph->saddr, 4); 7266a5f44d7STimo Teras return 4; 7276a5f44d7STimo Teras } 7286a5f44d7STimo Teras 7293b04dddeSStephen Hemminger static const struct header_ops ipgre_header_ops = { 7303b04dddeSStephen Hemminger .create = ipgre_header, 7316a5f44d7STimo Teras .parse = ipgre_header_parse, 7323b04dddeSStephen Hemminger }; 7333b04dddeSStephen Hemminger 7346a5f44d7STimo Teras #ifdef CONFIG_NET_IPGRE_BROADCAST 7351da177e4SLinus Torvalds static int ipgre_open(struct net_device *dev) 7361da177e4SLinus Torvalds { 7372941a486SPatrick McHardy struct ip_tunnel *t = netdev_priv(dev); 7381da177e4SLinus Torvalds 739f97c1e0cSJoe Perches if (ipv4_is_multicast(t->parms.iph.daddr)) { 740cbb1e85fSDavid S. Miller struct flowi4 fl4; 741cbb1e85fSDavid S. Miller struct rtable *rt; 742cbb1e85fSDavid S. Miller 743b57708adSNicolas Dichtel rt = ip_route_output_gre(t->net, &fl4, 74478fbfd8aSDavid S. Miller t->parms.iph.daddr, 74578fbfd8aSDavid S. Miller t->parms.iph.saddr, 74678fbfd8aSDavid S. Miller t->parms.o_key, 74778fbfd8aSDavid S. Miller RT_TOS(t->parms.iph.tos), 74878fbfd8aSDavid S. Miller t->parms.link); 749b23dd4feSDavid S. Miller if (IS_ERR(rt)) 7501da177e4SLinus Torvalds return -EADDRNOTAVAIL; 751d8d1f30bSChangli Gao dev = rt->dst.dev; 7521da177e4SLinus Torvalds ip_rt_put(rt); 75351456b29SIan Morris if (!__in_dev_get_rtnl(dev)) 7541da177e4SLinus Torvalds return -EADDRNOTAVAIL; 7551da177e4SLinus Torvalds t->mlink = dev->ifindex; 756e5ed6399SHerbert Xu ip_mc_inc_group(__in_dev_get_rtnl(dev), t->parms.iph.daddr); 7571da177e4SLinus Torvalds } 7581da177e4SLinus Torvalds return 0; 7591da177e4SLinus Torvalds } 7601da177e4SLinus Torvalds 7611da177e4SLinus Torvalds static int ipgre_close(struct net_device *dev) 7621da177e4SLinus Torvalds { 7632941a486SPatrick McHardy struct ip_tunnel *t = netdev_priv(dev); 764b8c26a33SStephen Hemminger 765f97c1e0cSJoe Perches if (ipv4_is_multicast(t->parms.iph.daddr) && t->mlink) { 7667fee0ca2SDenis V. Lunev struct in_device *in_dev; 767b57708adSNicolas Dichtel in_dev = inetdev_by_index(t->net, t->mlink); 7688723e1b4SEric Dumazet if (in_dev) 7691da177e4SLinus Torvalds ip_mc_dec_group(in_dev, t->parms.iph.daddr); 7701da177e4SLinus Torvalds } 7711da177e4SLinus Torvalds return 0; 7721da177e4SLinus Torvalds } 7731da177e4SLinus Torvalds #endif 7741da177e4SLinus Torvalds 775b8c26a33SStephen Hemminger static const struct net_device_ops ipgre_netdev_ops = { 776b8c26a33SStephen Hemminger .ndo_init = ipgre_tunnel_init, 777c5441932SPravin B Shelar .ndo_uninit = ip_tunnel_uninit, 778b8c26a33SStephen Hemminger #ifdef CONFIG_NET_IPGRE_BROADCAST 779b8c26a33SStephen Hemminger .ndo_open = ipgre_open, 780b8c26a33SStephen Hemminger .ndo_stop = ipgre_close, 781b8c26a33SStephen Hemminger #endif 782c5441932SPravin B Shelar .ndo_start_xmit = ipgre_xmit, 783b8c26a33SStephen Hemminger .ndo_do_ioctl = ipgre_tunnel_ioctl, 784c5441932SPravin B Shelar .ndo_change_mtu = ip_tunnel_change_mtu, 785c5441932SPravin B Shelar .ndo_get_stats64 = ip_tunnel_get_stats64, 7861e99584bSNicolas Dichtel .ndo_get_iflink = ip_tunnel_get_iflink, 787b8c26a33SStephen Hemminger }; 788b8c26a33SStephen Hemminger 7896b78f16eSEric Dumazet #define GRE_FEATURES (NETIF_F_SG | \ 7906b78f16eSEric Dumazet NETIF_F_FRAGLIST | \ 7916b78f16eSEric Dumazet NETIF_F_HIGHDMA | \ 7926b78f16eSEric Dumazet NETIF_F_HW_CSUM) 7936b78f16eSEric Dumazet 7941da177e4SLinus Torvalds static void ipgre_tunnel_setup(struct net_device *dev) 7951da177e4SLinus Torvalds { 796b8c26a33SStephen Hemminger dev->netdev_ops = &ipgre_netdev_ops; 7975a455275SNicolas Dichtel dev->type = ARPHRD_IPGRE; 798c5441932SPravin B Shelar ip_tunnel_setup(dev, ipgre_net_id); 799c5441932SPravin B Shelar } 8001da177e4SLinus Torvalds 801c5441932SPravin B Shelar static void __gre_tunnel_init(struct net_device *dev) 802c5441932SPravin B Shelar { 803c5441932SPravin B Shelar struct ip_tunnel *tunnel; 8044565e991STom Herbert int t_hlen; 805c5441932SPravin B Shelar 806c5441932SPravin B Shelar tunnel = netdev_priv(dev); 8074565e991STom Herbert tunnel->tun_hlen = ip_gre_calc_hlen(tunnel->parms.o_flags); 808c5441932SPravin B Shelar tunnel->parms.iph.protocol = IPPROTO_GRE; 809c5441932SPravin B Shelar 8104565e991STom Herbert tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen; 8114565e991STom Herbert 8124565e991STom Herbert t_hlen = tunnel->hlen + sizeof(struct iphdr); 8134565e991STom Herbert 8144565e991STom Herbert dev->needed_headroom = LL_MAX_HEADER + t_hlen + 4; 8154565e991STom Herbert dev->mtu = ETH_DATA_LEN - t_hlen - 4; 8166b78f16eSEric Dumazet 817b57708adSNicolas Dichtel dev->features |= GRE_FEATURES; 8186b78f16eSEric Dumazet dev->hw_features |= GRE_FEATURES; 819c5441932SPravin B Shelar 820c5441932SPravin B Shelar if (!(tunnel->parms.o_flags & TUNNEL_SEQ)) { 821c5441932SPravin B Shelar /* TCP offload with GRE SEQ is not supported. */ 822c5441932SPravin B Shelar dev->features |= NETIF_F_GSO_SOFTWARE; 823c5441932SPravin B Shelar dev->hw_features |= NETIF_F_GSO_SOFTWARE; 824c5441932SPravin B Shelar /* Can use a lockless transmit, unless we generate 825c5441932SPravin B Shelar * output sequences 826c5441932SPravin B Shelar */ 827c5441932SPravin B Shelar dev->features |= NETIF_F_LLTX; 828c5441932SPravin B Shelar } 8291da177e4SLinus Torvalds } 8301da177e4SLinus Torvalds 8311da177e4SLinus Torvalds static int ipgre_tunnel_init(struct net_device *dev) 8321da177e4SLinus Torvalds { 833c5441932SPravin B Shelar struct ip_tunnel *tunnel = netdev_priv(dev); 834c5441932SPravin B Shelar struct iphdr *iph = &tunnel->parms.iph; 8351da177e4SLinus Torvalds 836c5441932SPravin B Shelar __gre_tunnel_init(dev); 8371da177e4SLinus Torvalds 838c5441932SPravin B Shelar memcpy(dev->dev_addr, &iph->saddr, 4); 839c5441932SPravin B Shelar memcpy(dev->broadcast, &iph->daddr, 4); 8401da177e4SLinus Torvalds 841c5441932SPravin B Shelar dev->flags = IFF_NOARP; 84202875878SEric Dumazet netif_keep_dst(dev); 843c5441932SPravin B Shelar dev->addr_len = 4; 8441da177e4SLinus Torvalds 8451da177e4SLinus Torvalds if (iph->daddr) { 8461da177e4SLinus Torvalds #ifdef CONFIG_NET_IPGRE_BROADCAST 847f97c1e0cSJoe Perches if (ipv4_is_multicast(iph->daddr)) { 8481da177e4SLinus Torvalds if (!iph->saddr) 8491da177e4SLinus Torvalds return -EINVAL; 8501da177e4SLinus Torvalds dev->flags = IFF_BROADCAST; 8513b04dddeSStephen Hemminger dev->header_ops = &ipgre_header_ops; 8521da177e4SLinus Torvalds } 8531da177e4SLinus Torvalds #endif 854ee34c1ebSMichal Schmidt } else 8556a5f44d7STimo Teras dev->header_ops = &ipgre_header_ops; 8561da177e4SLinus Torvalds 857c5441932SPravin B Shelar return ip_tunnel_init(dev); 85860769a5dSEric Dumazet } 85960769a5dSEric Dumazet 8609f57c67cSPravin B Shelar static const struct gre_protocol ipgre_protocol = { 8619f57c67cSPravin B Shelar .handler = gre_rcv, 8629f57c67cSPravin B Shelar .err_handler = gre_err, 8631da177e4SLinus Torvalds }; 8641da177e4SLinus Torvalds 8652c8c1e72SAlexey Dobriyan static int __net_init ipgre_init_net(struct net *net) 86659a4c759SPavel Emelyanov { 867c5441932SPravin B Shelar return ip_tunnel_init_net(net, ipgre_net_id, &ipgre_link_ops, NULL); 86859a4c759SPavel Emelyanov } 86959a4c759SPavel Emelyanov 8702c8c1e72SAlexey Dobriyan static void __net_exit ipgre_exit_net(struct net *net) 87159a4c759SPavel Emelyanov { 872c5441932SPravin B Shelar struct ip_tunnel_net *itn = net_generic(net, ipgre_net_id); 8736c742e71SNicolas Dichtel ip_tunnel_delete_net(itn, &ipgre_link_ops); 87459a4c759SPavel Emelyanov } 87559a4c759SPavel Emelyanov 87659a4c759SPavel Emelyanov static struct pernet_operations ipgre_net_ops = { 87759a4c759SPavel Emelyanov .init = ipgre_init_net, 87859a4c759SPavel Emelyanov .exit = ipgre_exit_net, 879cfb8fbf2SEric W. Biederman .id = &ipgre_net_id, 880c5441932SPravin B Shelar .size = sizeof(struct ip_tunnel_net), 88159a4c759SPavel Emelyanov }; 8821da177e4SLinus Torvalds 883c19e654dSHerbert Xu static int ipgre_tunnel_validate(struct nlattr *tb[], struct nlattr *data[]) 884c19e654dSHerbert Xu { 885c19e654dSHerbert Xu __be16 flags; 886c19e654dSHerbert Xu 887c19e654dSHerbert Xu if (!data) 888c19e654dSHerbert Xu return 0; 889c19e654dSHerbert Xu 890c19e654dSHerbert Xu flags = 0; 891c19e654dSHerbert Xu if (data[IFLA_GRE_IFLAGS]) 892c19e654dSHerbert Xu flags |= nla_get_be16(data[IFLA_GRE_IFLAGS]); 893c19e654dSHerbert Xu if (data[IFLA_GRE_OFLAGS]) 894c19e654dSHerbert Xu flags |= nla_get_be16(data[IFLA_GRE_OFLAGS]); 895c19e654dSHerbert Xu if (flags & (GRE_VERSION|GRE_ROUTING)) 896c19e654dSHerbert Xu return -EINVAL; 897c19e654dSHerbert Xu 898c19e654dSHerbert Xu return 0; 899c19e654dSHerbert Xu } 900c19e654dSHerbert Xu 901e1a80002SHerbert Xu static int ipgre_tap_validate(struct nlattr *tb[], struct nlattr *data[]) 902e1a80002SHerbert Xu { 903e1a80002SHerbert Xu __be32 daddr; 904e1a80002SHerbert Xu 905e1a80002SHerbert Xu if (tb[IFLA_ADDRESS]) { 906e1a80002SHerbert Xu if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN) 907e1a80002SHerbert Xu return -EINVAL; 908e1a80002SHerbert Xu if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS]))) 909e1a80002SHerbert Xu return -EADDRNOTAVAIL; 910e1a80002SHerbert Xu } 911e1a80002SHerbert Xu 912e1a80002SHerbert Xu if (!data) 913e1a80002SHerbert Xu goto out; 914e1a80002SHerbert Xu 915e1a80002SHerbert Xu if (data[IFLA_GRE_REMOTE]) { 916e1a80002SHerbert Xu memcpy(&daddr, nla_data(data[IFLA_GRE_REMOTE]), 4); 917e1a80002SHerbert Xu if (!daddr) 918e1a80002SHerbert Xu return -EINVAL; 919e1a80002SHerbert Xu } 920e1a80002SHerbert Xu 921e1a80002SHerbert Xu out: 922e1a80002SHerbert Xu return ipgre_tunnel_validate(tb, data); 923e1a80002SHerbert Xu } 924e1a80002SHerbert Xu 9252e15ea39SPravin B Shelar static void ipgre_netlink_parms(struct net_device *dev, 9262e15ea39SPravin B Shelar struct nlattr *data[], 9272e15ea39SPravin B Shelar struct nlattr *tb[], 928c19e654dSHerbert Xu struct ip_tunnel_parm *parms) 929c19e654dSHerbert Xu { 9307bb82d92SHerbert Xu memset(parms, 0, sizeof(*parms)); 931c19e654dSHerbert Xu 932c19e654dSHerbert Xu parms->iph.protocol = IPPROTO_GRE; 933c19e654dSHerbert Xu 934c19e654dSHerbert Xu if (!data) 935c19e654dSHerbert Xu return; 936c19e654dSHerbert Xu 937c19e654dSHerbert Xu if (data[IFLA_GRE_LINK]) 938c19e654dSHerbert Xu parms->link = nla_get_u32(data[IFLA_GRE_LINK]); 939c19e654dSHerbert Xu 940c19e654dSHerbert Xu if (data[IFLA_GRE_IFLAGS]) 941c5441932SPravin B Shelar parms->i_flags = gre_flags_to_tnl_flags(nla_get_be16(data[IFLA_GRE_IFLAGS])); 942c19e654dSHerbert Xu 943c19e654dSHerbert Xu if (data[IFLA_GRE_OFLAGS]) 944c5441932SPravin B Shelar parms->o_flags = gre_flags_to_tnl_flags(nla_get_be16(data[IFLA_GRE_OFLAGS])); 945c19e654dSHerbert Xu 946c19e654dSHerbert Xu if (data[IFLA_GRE_IKEY]) 947c19e654dSHerbert Xu parms->i_key = nla_get_be32(data[IFLA_GRE_IKEY]); 948c19e654dSHerbert Xu 949c19e654dSHerbert Xu if (data[IFLA_GRE_OKEY]) 950c19e654dSHerbert Xu parms->o_key = nla_get_be32(data[IFLA_GRE_OKEY]); 951c19e654dSHerbert Xu 952c19e654dSHerbert Xu if (data[IFLA_GRE_LOCAL]) 95367b61f6cSJiri Benc parms->iph.saddr = nla_get_in_addr(data[IFLA_GRE_LOCAL]); 954c19e654dSHerbert Xu 955c19e654dSHerbert Xu if (data[IFLA_GRE_REMOTE]) 95667b61f6cSJiri Benc parms->iph.daddr = nla_get_in_addr(data[IFLA_GRE_REMOTE]); 957c19e654dSHerbert Xu 958c19e654dSHerbert Xu if (data[IFLA_GRE_TTL]) 959c19e654dSHerbert Xu parms->iph.ttl = nla_get_u8(data[IFLA_GRE_TTL]); 960c19e654dSHerbert Xu 961c19e654dSHerbert Xu if (data[IFLA_GRE_TOS]) 962c19e654dSHerbert Xu parms->iph.tos = nla_get_u8(data[IFLA_GRE_TOS]); 963c19e654dSHerbert Xu 964c19e654dSHerbert Xu if (!data[IFLA_GRE_PMTUDISC] || nla_get_u8(data[IFLA_GRE_PMTUDISC])) 965c19e654dSHerbert Xu parms->iph.frag_off = htons(IP_DF); 9662e15ea39SPravin B Shelar 9672e15ea39SPravin B Shelar if (data[IFLA_GRE_COLLECT_METADATA]) { 9682e15ea39SPravin B Shelar struct ip_tunnel *t = netdev_priv(dev); 9692e15ea39SPravin B Shelar 9702e15ea39SPravin B Shelar t->collect_md = true; 9712e15ea39SPravin B Shelar } 972c19e654dSHerbert Xu } 973c19e654dSHerbert Xu 9744565e991STom Herbert /* This function returns true when ENCAP attributes are present in the nl msg */ 9754565e991STom Herbert static bool ipgre_netlink_encap_parms(struct nlattr *data[], 9764565e991STom Herbert struct ip_tunnel_encap *ipencap) 9774565e991STom Herbert { 9784565e991STom Herbert bool ret = false; 9794565e991STom Herbert 9804565e991STom Herbert memset(ipencap, 0, sizeof(*ipencap)); 9814565e991STom Herbert 9824565e991STom Herbert if (!data) 9834565e991STom Herbert return ret; 9844565e991STom Herbert 9854565e991STom Herbert if (data[IFLA_GRE_ENCAP_TYPE]) { 9864565e991STom Herbert ret = true; 9874565e991STom Herbert ipencap->type = nla_get_u16(data[IFLA_GRE_ENCAP_TYPE]); 9884565e991STom Herbert } 9894565e991STom Herbert 9904565e991STom Herbert if (data[IFLA_GRE_ENCAP_FLAGS]) { 9914565e991STom Herbert ret = true; 9924565e991STom Herbert ipencap->flags = nla_get_u16(data[IFLA_GRE_ENCAP_FLAGS]); 9934565e991STom Herbert } 9944565e991STom Herbert 9954565e991STom Herbert if (data[IFLA_GRE_ENCAP_SPORT]) { 9964565e991STom Herbert ret = true; 9973e97fa70SSabrina Dubroca ipencap->sport = nla_get_be16(data[IFLA_GRE_ENCAP_SPORT]); 9984565e991STom Herbert } 9994565e991STom Herbert 10004565e991STom Herbert if (data[IFLA_GRE_ENCAP_DPORT]) { 10014565e991STom Herbert ret = true; 10023e97fa70SSabrina Dubroca ipencap->dport = nla_get_be16(data[IFLA_GRE_ENCAP_DPORT]); 10034565e991STom Herbert } 10044565e991STom Herbert 10054565e991STom Herbert return ret; 10064565e991STom Herbert } 10074565e991STom Herbert 1008c5441932SPravin B Shelar static int gre_tap_init(struct net_device *dev) 1009e1a80002SHerbert Xu { 1010c5441932SPravin B Shelar __gre_tunnel_init(dev); 1011bec94d43Sstephen hemminger dev->priv_flags |= IFF_LIVE_ADDR_CHANGE; 1012e1a80002SHerbert Xu 1013c5441932SPravin B Shelar return ip_tunnel_init(dev); 1014e1a80002SHerbert Xu } 1015e1a80002SHerbert Xu 1016c5441932SPravin B Shelar static const struct net_device_ops gre_tap_netdev_ops = { 1017c5441932SPravin B Shelar .ndo_init = gre_tap_init, 1018c5441932SPravin B Shelar .ndo_uninit = ip_tunnel_uninit, 1019c5441932SPravin B Shelar .ndo_start_xmit = gre_tap_xmit, 1020b8c26a33SStephen Hemminger .ndo_set_mac_address = eth_mac_addr, 1021b8c26a33SStephen Hemminger .ndo_validate_addr = eth_validate_addr, 1022c5441932SPravin B Shelar .ndo_change_mtu = ip_tunnel_change_mtu, 1023c5441932SPravin B Shelar .ndo_get_stats64 = ip_tunnel_get_stats64, 10241e99584bSNicolas Dichtel .ndo_get_iflink = ip_tunnel_get_iflink, 1025b8c26a33SStephen Hemminger }; 1026b8c26a33SStephen Hemminger 1027e1a80002SHerbert Xu static void ipgre_tap_setup(struct net_device *dev) 1028e1a80002SHerbert Xu { 1029e1a80002SHerbert Xu ether_setup(dev); 1030c5441932SPravin B Shelar dev->netdev_ops = &gre_tap_netdev_ops; 1031f8c1b7ceSstephen hemminger dev->priv_flags |= IFF_LIVE_ADDR_CHANGE; 1032c5441932SPravin B Shelar ip_tunnel_setup(dev, gre_tap_net_id); 1033e1a80002SHerbert Xu } 1034e1a80002SHerbert Xu 1035c5441932SPravin B Shelar static int ipgre_newlink(struct net *src_net, struct net_device *dev, 1036c5441932SPravin B Shelar struct nlattr *tb[], struct nlattr *data[]) 1037c19e654dSHerbert Xu { 1038c5441932SPravin B Shelar struct ip_tunnel_parm p; 10394565e991STom Herbert struct ip_tunnel_encap ipencap; 10404565e991STom Herbert 10414565e991STom Herbert if (ipgre_netlink_encap_parms(data, &ipencap)) { 10424565e991STom Herbert struct ip_tunnel *t = netdev_priv(dev); 10434565e991STom Herbert int err = ip_tunnel_encap_setup(t, &ipencap); 10444565e991STom Herbert 10454565e991STom Herbert if (err < 0) 10464565e991STom Herbert return err; 10474565e991STom Herbert } 1048c19e654dSHerbert Xu 10492e15ea39SPravin B Shelar ipgre_netlink_parms(dev, data, tb, &p); 1050c5441932SPravin B Shelar return ip_tunnel_newlink(dev, tb, &p); 1051c19e654dSHerbert Xu } 1052c19e654dSHerbert Xu 1053c19e654dSHerbert Xu static int ipgre_changelink(struct net_device *dev, struct nlattr *tb[], 1054c19e654dSHerbert Xu struct nlattr *data[]) 1055c19e654dSHerbert Xu { 1056c19e654dSHerbert Xu struct ip_tunnel_parm p; 10574565e991STom Herbert struct ip_tunnel_encap ipencap; 10584565e991STom Herbert 10594565e991STom Herbert if (ipgre_netlink_encap_parms(data, &ipencap)) { 10604565e991STom Herbert struct ip_tunnel *t = netdev_priv(dev); 10614565e991STom Herbert int err = ip_tunnel_encap_setup(t, &ipencap); 10624565e991STom Herbert 10634565e991STom Herbert if (err < 0) 10644565e991STom Herbert return err; 10654565e991STom Herbert } 1066c19e654dSHerbert Xu 10672e15ea39SPravin B Shelar ipgre_netlink_parms(dev, data, tb, &p); 1068c5441932SPravin B Shelar return ip_tunnel_changelink(dev, tb, &p); 1069c19e654dSHerbert Xu } 1070c19e654dSHerbert Xu 1071c19e654dSHerbert Xu static size_t ipgre_get_size(const struct net_device *dev) 1072c19e654dSHerbert Xu { 1073c19e654dSHerbert Xu return 1074c19e654dSHerbert Xu /* IFLA_GRE_LINK */ 1075c19e654dSHerbert Xu nla_total_size(4) + 1076c19e654dSHerbert Xu /* IFLA_GRE_IFLAGS */ 1077c19e654dSHerbert Xu nla_total_size(2) + 1078c19e654dSHerbert Xu /* IFLA_GRE_OFLAGS */ 1079c19e654dSHerbert Xu nla_total_size(2) + 1080c19e654dSHerbert Xu /* IFLA_GRE_IKEY */ 1081c19e654dSHerbert Xu nla_total_size(4) + 1082c19e654dSHerbert Xu /* IFLA_GRE_OKEY */ 1083c19e654dSHerbert Xu nla_total_size(4) + 1084c19e654dSHerbert Xu /* IFLA_GRE_LOCAL */ 1085c19e654dSHerbert Xu nla_total_size(4) + 1086c19e654dSHerbert Xu /* IFLA_GRE_REMOTE */ 1087c19e654dSHerbert Xu nla_total_size(4) + 1088c19e654dSHerbert Xu /* IFLA_GRE_TTL */ 1089c19e654dSHerbert Xu nla_total_size(1) + 1090c19e654dSHerbert Xu /* IFLA_GRE_TOS */ 1091c19e654dSHerbert Xu nla_total_size(1) + 1092c19e654dSHerbert Xu /* IFLA_GRE_PMTUDISC */ 1093c19e654dSHerbert Xu nla_total_size(1) + 10944565e991STom Herbert /* IFLA_GRE_ENCAP_TYPE */ 10954565e991STom Herbert nla_total_size(2) + 10964565e991STom Herbert /* IFLA_GRE_ENCAP_FLAGS */ 10974565e991STom Herbert nla_total_size(2) + 10984565e991STom Herbert /* IFLA_GRE_ENCAP_SPORT */ 10994565e991STom Herbert nla_total_size(2) + 11004565e991STom Herbert /* IFLA_GRE_ENCAP_DPORT */ 11014565e991STom Herbert nla_total_size(2) + 11022e15ea39SPravin B Shelar /* IFLA_GRE_COLLECT_METADATA */ 11032e15ea39SPravin B Shelar nla_total_size(0) + 1104c19e654dSHerbert Xu 0; 1105c19e654dSHerbert Xu } 1106c19e654dSHerbert Xu 1107c19e654dSHerbert Xu static int ipgre_fill_info(struct sk_buff *skb, const struct net_device *dev) 1108c19e654dSHerbert Xu { 1109c19e654dSHerbert Xu struct ip_tunnel *t = netdev_priv(dev); 1110c19e654dSHerbert Xu struct ip_tunnel_parm *p = &t->parms; 1111c19e654dSHerbert Xu 1112f3756b79SDavid S. Miller if (nla_put_u32(skb, IFLA_GRE_LINK, p->link) || 1113c5441932SPravin B Shelar nla_put_be16(skb, IFLA_GRE_IFLAGS, tnl_flags_to_gre_flags(p->i_flags)) || 1114c5441932SPravin B Shelar nla_put_be16(skb, IFLA_GRE_OFLAGS, tnl_flags_to_gre_flags(p->o_flags)) || 1115f3756b79SDavid S. Miller nla_put_be32(skb, IFLA_GRE_IKEY, p->i_key) || 1116f3756b79SDavid S. Miller nla_put_be32(skb, IFLA_GRE_OKEY, p->o_key) || 1117930345eaSJiri Benc nla_put_in_addr(skb, IFLA_GRE_LOCAL, p->iph.saddr) || 1118930345eaSJiri Benc nla_put_in_addr(skb, IFLA_GRE_REMOTE, p->iph.daddr) || 1119f3756b79SDavid S. Miller nla_put_u8(skb, IFLA_GRE_TTL, p->iph.ttl) || 1120f3756b79SDavid S. Miller nla_put_u8(skb, IFLA_GRE_TOS, p->iph.tos) || 1121f3756b79SDavid S. Miller nla_put_u8(skb, IFLA_GRE_PMTUDISC, 1122f3756b79SDavid S. Miller !!(p->iph.frag_off & htons(IP_DF)))) 1123f3756b79SDavid S. Miller goto nla_put_failure; 11244565e991STom Herbert 11254565e991STom Herbert if (nla_put_u16(skb, IFLA_GRE_ENCAP_TYPE, 11264565e991STom Herbert t->encap.type) || 11273e97fa70SSabrina Dubroca nla_put_be16(skb, IFLA_GRE_ENCAP_SPORT, 11284565e991STom Herbert t->encap.sport) || 11293e97fa70SSabrina Dubroca nla_put_be16(skb, IFLA_GRE_ENCAP_DPORT, 11304565e991STom Herbert t->encap.dport) || 11314565e991STom Herbert nla_put_u16(skb, IFLA_GRE_ENCAP_FLAGS, 1132e1b2cb65STom Herbert t->encap.flags)) 11334565e991STom Herbert goto nla_put_failure; 11344565e991STom Herbert 11352e15ea39SPravin B Shelar if (t->collect_md) { 11362e15ea39SPravin B Shelar if (nla_put_flag(skb, IFLA_GRE_COLLECT_METADATA)) 11372e15ea39SPravin B Shelar goto nla_put_failure; 11382e15ea39SPravin B Shelar } 11392e15ea39SPravin B Shelar 1140c19e654dSHerbert Xu return 0; 1141c19e654dSHerbert Xu 1142c19e654dSHerbert Xu nla_put_failure: 1143c19e654dSHerbert Xu return -EMSGSIZE; 1144c19e654dSHerbert Xu } 1145c19e654dSHerbert Xu 1146c19e654dSHerbert Xu static const struct nla_policy ipgre_policy[IFLA_GRE_MAX + 1] = { 1147c19e654dSHerbert Xu [IFLA_GRE_LINK] = { .type = NLA_U32 }, 1148c19e654dSHerbert Xu [IFLA_GRE_IFLAGS] = { .type = NLA_U16 }, 1149c19e654dSHerbert Xu [IFLA_GRE_OFLAGS] = { .type = NLA_U16 }, 1150c19e654dSHerbert Xu [IFLA_GRE_IKEY] = { .type = NLA_U32 }, 1151c19e654dSHerbert Xu [IFLA_GRE_OKEY] = { .type = NLA_U32 }, 11524d74f8baSPatrick McHardy [IFLA_GRE_LOCAL] = { .len = FIELD_SIZEOF(struct iphdr, saddr) }, 11534d74f8baSPatrick McHardy [IFLA_GRE_REMOTE] = { .len = FIELD_SIZEOF(struct iphdr, daddr) }, 1154c19e654dSHerbert Xu [IFLA_GRE_TTL] = { .type = NLA_U8 }, 1155c19e654dSHerbert Xu [IFLA_GRE_TOS] = { .type = NLA_U8 }, 1156c19e654dSHerbert Xu [IFLA_GRE_PMTUDISC] = { .type = NLA_U8 }, 11574565e991STom Herbert [IFLA_GRE_ENCAP_TYPE] = { .type = NLA_U16 }, 11584565e991STom Herbert [IFLA_GRE_ENCAP_FLAGS] = { .type = NLA_U16 }, 11594565e991STom Herbert [IFLA_GRE_ENCAP_SPORT] = { .type = NLA_U16 }, 11604565e991STom Herbert [IFLA_GRE_ENCAP_DPORT] = { .type = NLA_U16 }, 11612e15ea39SPravin B Shelar [IFLA_GRE_COLLECT_METADATA] = { .type = NLA_FLAG }, 1162c19e654dSHerbert Xu }; 1163c19e654dSHerbert Xu 1164c19e654dSHerbert Xu static struct rtnl_link_ops ipgre_link_ops __read_mostly = { 1165c19e654dSHerbert Xu .kind = "gre", 1166c19e654dSHerbert Xu .maxtype = IFLA_GRE_MAX, 1167c19e654dSHerbert Xu .policy = ipgre_policy, 1168c19e654dSHerbert Xu .priv_size = sizeof(struct ip_tunnel), 1169c19e654dSHerbert Xu .setup = ipgre_tunnel_setup, 1170c19e654dSHerbert Xu .validate = ipgre_tunnel_validate, 1171c19e654dSHerbert Xu .newlink = ipgre_newlink, 1172c19e654dSHerbert Xu .changelink = ipgre_changelink, 1173c5441932SPravin B Shelar .dellink = ip_tunnel_dellink, 1174c19e654dSHerbert Xu .get_size = ipgre_get_size, 1175c19e654dSHerbert Xu .fill_info = ipgre_fill_info, 11761728d4faSNicolas Dichtel .get_link_net = ip_tunnel_get_link_net, 1177c19e654dSHerbert Xu }; 1178c19e654dSHerbert Xu 1179e1a80002SHerbert Xu static struct rtnl_link_ops ipgre_tap_ops __read_mostly = { 1180e1a80002SHerbert Xu .kind = "gretap", 1181e1a80002SHerbert Xu .maxtype = IFLA_GRE_MAX, 1182e1a80002SHerbert Xu .policy = ipgre_policy, 1183e1a80002SHerbert Xu .priv_size = sizeof(struct ip_tunnel), 1184e1a80002SHerbert Xu .setup = ipgre_tap_setup, 1185e1a80002SHerbert Xu .validate = ipgre_tap_validate, 1186e1a80002SHerbert Xu .newlink = ipgre_newlink, 1187e1a80002SHerbert Xu .changelink = ipgre_changelink, 1188c5441932SPravin B Shelar .dellink = ip_tunnel_dellink, 1189e1a80002SHerbert Xu .get_size = ipgre_get_size, 1190e1a80002SHerbert Xu .fill_info = ipgre_fill_info, 11911728d4faSNicolas Dichtel .get_link_net = ip_tunnel_get_link_net, 1192e1a80002SHerbert Xu }; 1193e1a80002SHerbert Xu 1194b2acd1dcSPravin B Shelar struct net_device *gretap_fb_dev_create(struct net *net, const char *name, 1195b2acd1dcSPravin B Shelar u8 name_assign_type) 1196b2acd1dcSPravin B Shelar { 1197b2acd1dcSPravin B Shelar struct nlattr *tb[IFLA_MAX + 1]; 1198b2acd1dcSPravin B Shelar struct net_device *dev; 1199b2acd1dcSPravin B Shelar struct ip_tunnel *t; 1200b2acd1dcSPravin B Shelar int err; 1201b2acd1dcSPravin B Shelar 1202b2acd1dcSPravin B Shelar memset(&tb, 0, sizeof(tb)); 1203b2acd1dcSPravin B Shelar 1204b2acd1dcSPravin B Shelar dev = rtnl_create_link(net, name, name_assign_type, 1205b2acd1dcSPravin B Shelar &ipgre_tap_ops, tb); 1206b2acd1dcSPravin B Shelar if (IS_ERR(dev)) 1207b2acd1dcSPravin B Shelar return dev; 1208b2acd1dcSPravin B Shelar 1209b2acd1dcSPravin B Shelar /* Configure flow based GRE device. */ 1210b2acd1dcSPravin B Shelar t = netdev_priv(dev); 1211b2acd1dcSPravin B Shelar t->collect_md = true; 1212b2acd1dcSPravin B Shelar 1213b2acd1dcSPravin B Shelar err = ipgre_newlink(net, dev, tb, NULL); 1214b2acd1dcSPravin B Shelar if (err < 0) 1215b2acd1dcSPravin B Shelar goto out; 1216b2acd1dcSPravin B Shelar return dev; 1217b2acd1dcSPravin B Shelar out: 1218b2acd1dcSPravin B Shelar free_netdev(dev); 1219b2acd1dcSPravin B Shelar return ERR_PTR(err); 1220b2acd1dcSPravin B Shelar } 1221b2acd1dcSPravin B Shelar EXPORT_SYMBOL_GPL(gretap_fb_dev_create); 1222b2acd1dcSPravin B Shelar 1223c5441932SPravin B Shelar static int __net_init ipgre_tap_init_net(struct net *net) 1224c5441932SPravin B Shelar { 12252e15ea39SPravin B Shelar return ip_tunnel_init_net(net, gre_tap_net_id, &ipgre_tap_ops, "gretap0"); 1226c5441932SPravin B Shelar } 1227c5441932SPravin B Shelar 1228c5441932SPravin B Shelar static void __net_exit ipgre_tap_exit_net(struct net *net) 1229c5441932SPravin B Shelar { 1230c5441932SPravin B Shelar struct ip_tunnel_net *itn = net_generic(net, gre_tap_net_id); 12316c742e71SNicolas Dichtel ip_tunnel_delete_net(itn, &ipgre_tap_ops); 1232c5441932SPravin B Shelar } 1233c5441932SPravin B Shelar 1234c5441932SPravin B Shelar static struct pernet_operations ipgre_tap_net_ops = { 1235c5441932SPravin B Shelar .init = ipgre_tap_init_net, 1236c5441932SPravin B Shelar .exit = ipgre_tap_exit_net, 1237c5441932SPravin B Shelar .id = &gre_tap_net_id, 1238c5441932SPravin B Shelar .size = sizeof(struct ip_tunnel_net), 1239c5441932SPravin B Shelar }; 12401da177e4SLinus Torvalds 12411da177e4SLinus Torvalds static int __init ipgre_init(void) 12421da177e4SLinus Torvalds { 12431da177e4SLinus Torvalds int err; 12441da177e4SLinus Torvalds 1245058bd4d2SJoe Perches pr_info("GRE over IPv4 tunneling driver\n"); 12461da177e4SLinus Torvalds 1247cfb8fbf2SEric W. Biederman err = register_pernet_device(&ipgre_net_ops); 124859a4c759SPavel Emelyanov if (err < 0) 1249c2892f02SAlexey Dobriyan return err; 1250c2892f02SAlexey Dobriyan 1251c5441932SPravin B Shelar err = register_pernet_device(&ipgre_tap_net_ops); 1252c5441932SPravin B Shelar if (err < 0) 1253c5441932SPravin B Shelar goto pnet_tap_faied; 1254c5441932SPravin B Shelar 12559f57c67cSPravin B Shelar err = gre_add_protocol(&ipgre_protocol, GREPROTO_CISCO); 1256c2892f02SAlexey Dobriyan if (err < 0) { 1257058bd4d2SJoe Perches pr_info("%s: can't add protocol\n", __func__); 1258c2892f02SAlexey Dobriyan goto add_proto_failed; 1259c2892f02SAlexey Dobriyan } 12607daa0004SPavel Emelyanov 1261c19e654dSHerbert Xu err = rtnl_link_register(&ipgre_link_ops); 1262c19e654dSHerbert Xu if (err < 0) 1263c19e654dSHerbert Xu goto rtnl_link_failed; 1264c19e654dSHerbert Xu 1265e1a80002SHerbert Xu err = rtnl_link_register(&ipgre_tap_ops); 1266e1a80002SHerbert Xu if (err < 0) 1267e1a80002SHerbert Xu goto tap_ops_failed; 1268e1a80002SHerbert Xu 1269c5441932SPravin B Shelar return 0; 1270c19e654dSHerbert Xu 1271e1a80002SHerbert Xu tap_ops_failed: 1272e1a80002SHerbert Xu rtnl_link_unregister(&ipgre_link_ops); 1273c19e654dSHerbert Xu rtnl_link_failed: 12749f57c67cSPravin B Shelar gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO); 1275c2892f02SAlexey Dobriyan add_proto_failed: 1276c5441932SPravin B Shelar unregister_pernet_device(&ipgre_tap_net_ops); 1277c5441932SPravin B Shelar pnet_tap_faied: 1278c2892f02SAlexey Dobriyan unregister_pernet_device(&ipgre_net_ops); 1279c5441932SPravin B Shelar return err; 12801da177e4SLinus Torvalds } 12811da177e4SLinus Torvalds 1282db44575fSAlexey Kuznetsov static void __exit ipgre_fini(void) 12831da177e4SLinus Torvalds { 1284e1a80002SHerbert Xu rtnl_link_unregister(&ipgre_tap_ops); 1285c19e654dSHerbert Xu rtnl_link_unregister(&ipgre_link_ops); 12869f57c67cSPravin B Shelar gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO); 1287c5441932SPravin B Shelar unregister_pernet_device(&ipgre_tap_net_ops); 1288c2892f02SAlexey Dobriyan unregister_pernet_device(&ipgre_net_ops); 12891da177e4SLinus Torvalds } 12901da177e4SLinus Torvalds 12911da177e4SLinus Torvalds module_init(ipgre_init); 12921da177e4SLinus Torvalds module_exit(ipgre_fini); 12931da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 12944d74f8baSPatrick McHardy MODULE_ALIAS_RTNL_LINK("gre"); 12954d74f8baSPatrick McHardy MODULE_ALIAS_RTNL_LINK("gretap"); 12968909c9adSVasiliy Kulikov MODULE_ALIAS_NETDEV("gre0"); 1297c5441932SPravin B Shelar MODULE_ALIAS_NETDEV("gretap0"); 1298