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> 281da177e4SLinus Torvalds #include <linux/init.h> 291da177e4SLinus Torvalds #include <linux/in6.h> 301da177e4SLinus Torvalds #include <linux/inetdevice.h> 311da177e4SLinus Torvalds #include <linux/igmp.h> 321da177e4SLinus Torvalds #include <linux/netfilter_ipv4.h> 33e1a80002SHerbert Xu #include <linux/etherdevice.h> 3446f25dffSKris Katterjohn #include <linux/if_ether.h> 351da177e4SLinus Torvalds 361da177e4SLinus Torvalds #include <net/sock.h> 371da177e4SLinus Torvalds #include <net/ip.h> 381da177e4SLinus Torvalds #include <net/icmp.h> 391da177e4SLinus Torvalds #include <net/protocol.h> 40c5441932SPravin B Shelar #include <net/ip_tunnels.h> 411da177e4SLinus Torvalds #include <net/arp.h> 421da177e4SLinus Torvalds #include <net/checksum.h> 431da177e4SLinus Torvalds #include <net/dsfield.h> 441da177e4SLinus Torvalds #include <net/inet_ecn.h> 451da177e4SLinus Torvalds #include <net/xfrm.h> 4659a4c759SPavel Emelyanov #include <net/net_namespace.h> 4759a4c759SPavel Emelyanov #include <net/netns/generic.h> 48c19e654dSHerbert Xu #include <net/rtnetlink.h> 4900959adeSDmitry Kozlov #include <net/gre.h> 501da177e4SLinus Torvalds 51dfd56b8bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6) 521da177e4SLinus Torvalds #include <net/ipv6.h> 531da177e4SLinus Torvalds #include <net/ip6_fib.h> 541da177e4SLinus Torvalds #include <net/ip6_route.h> 551da177e4SLinus Torvalds #endif 561da177e4SLinus Torvalds 571da177e4SLinus Torvalds /* 581da177e4SLinus Torvalds Problems & solutions 591da177e4SLinus Torvalds -------------------- 601da177e4SLinus Torvalds 611da177e4SLinus Torvalds 1. The most important issue is detecting local dead loops. 621da177e4SLinus Torvalds They would cause complete host lockup in transmit, which 631da177e4SLinus Torvalds would be "resolved" by stack overflow or, if queueing is enabled, 641da177e4SLinus Torvalds with infinite looping in net_bh. 651da177e4SLinus Torvalds 661da177e4SLinus Torvalds We cannot track such dead loops during route installation, 671da177e4SLinus Torvalds it is infeasible task. The most general solutions would be 681da177e4SLinus Torvalds to keep skb->encapsulation counter (sort of local ttl), 696d0722a2SEric Dumazet and silently drop packet when it expires. It is a good 70bff52857Sstephen hemminger solution, but it supposes maintaining new variable in ALL 711da177e4SLinus Torvalds skb, even if no tunneling is used. 721da177e4SLinus Torvalds 736d0722a2SEric Dumazet Current solution: xmit_recursion breaks dead loops. This is a percpu 746d0722a2SEric Dumazet counter, since when we enter the first ndo_xmit(), cpu migration is 756d0722a2SEric Dumazet forbidden. We force an exit if this counter reaches RECURSION_LIMIT 761da177e4SLinus Torvalds 771da177e4SLinus Torvalds 2. Networking dead loops would not kill routers, but would really 781da177e4SLinus Torvalds kill network. IP hop limit plays role of "t->recursion" in this case, 791da177e4SLinus Torvalds if we copy it from packet being encapsulated to upper header. 801da177e4SLinus Torvalds It is very good solution, but it introduces two problems: 811da177e4SLinus Torvalds 821da177e4SLinus Torvalds - Routing protocols, using packets with ttl=1 (OSPF, RIP2), 831da177e4SLinus Torvalds do not work over tunnels. 841da177e4SLinus Torvalds - traceroute does not work. I planned to relay ICMP from tunnel, 851da177e4SLinus Torvalds so that this problem would be solved and traceroute output 861da177e4SLinus Torvalds would even more informative. This idea appeared to be wrong: 871da177e4SLinus Torvalds only Linux complies to rfc1812 now (yes, guys, Linux is the only 881da177e4SLinus Torvalds true router now :-)), all routers (at least, in neighbourhood of mine) 891da177e4SLinus Torvalds return only 8 bytes of payload. It is the end. 901da177e4SLinus Torvalds 911da177e4SLinus Torvalds Hence, if we want that OSPF worked or traceroute said something reasonable, 921da177e4SLinus Torvalds we should search for another solution. 931da177e4SLinus Torvalds 941da177e4SLinus Torvalds One of them is to parse packet trying to detect inner encapsulation 951da177e4SLinus Torvalds made by our node. It is difficult or even impossible, especially, 96bff52857Sstephen hemminger taking into account fragmentation. TO be short, ttl is not solution at all. 971da177e4SLinus Torvalds 981da177e4SLinus Torvalds Current solution: The solution was UNEXPECTEDLY SIMPLE. 991da177e4SLinus Torvalds We force DF flag on tunnels with preconfigured hop limit, 1001da177e4SLinus Torvalds that is ALL. :-) Well, it does not remove the problem completely, 1011da177e4SLinus Torvalds but exponential growth of network traffic is changed to linear 1021da177e4SLinus Torvalds (branches, that exceed pmtu are pruned) and tunnel mtu 103bff52857Sstephen hemminger rapidly degrades to value <68, where looping stops. 1041da177e4SLinus Torvalds Yes, it is not good if there exists a router in the loop, 1051da177e4SLinus Torvalds which does not force DF, even when encapsulating packets have DF set. 1061da177e4SLinus Torvalds But it is not our problem! Nobody could accuse us, we made 1071da177e4SLinus Torvalds all that we could make. Even if it is your gated who injected 1081da177e4SLinus Torvalds fatal route to network, even if it were you who configured 1091da177e4SLinus Torvalds fatal static route: you are innocent. :-) 1101da177e4SLinus Torvalds 1111da177e4SLinus Torvalds Alexey Kuznetsov. 1121da177e4SLinus Torvalds */ 1131da177e4SLinus Torvalds 114eccc1bb8Sstephen hemminger static bool log_ecn_error = true; 115eccc1bb8Sstephen hemminger module_param(log_ecn_error, bool, 0644); 116eccc1bb8Sstephen hemminger MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN"); 117eccc1bb8Sstephen hemminger 118c19e654dSHerbert Xu static struct rtnl_link_ops ipgre_link_ops __read_mostly; 1191da177e4SLinus Torvalds static int ipgre_tunnel_init(struct net_device *dev); 120eb8ce741SPavel Emelyanov 121f99189b1SEric Dumazet static int ipgre_net_id __read_mostly; 122c5441932SPravin B Shelar static int gre_tap_net_id __read_mostly; 123eb8ce741SPavel Emelyanov 124bda7bb46SPravin B Shelar static int ipgre_err(struct sk_buff *skb, u32 info, 125bda7bb46SPravin B Shelar const struct tnl_ptk_info *tpi) 1261da177e4SLinus Torvalds { 1271da177e4SLinus Torvalds 128071f92d0SRami Rosen /* All the routers (except for Linux) return only 1291da177e4SLinus Torvalds 8 bytes of packet payload. It means, that precise relaying of 1301da177e4SLinus Torvalds ICMP in the real Internet is absolutely infeasible. 1311da177e4SLinus Torvalds 1321da177e4SLinus Torvalds Moreover, Cisco "wise men" put GRE key to the third word 133c5441932SPravin B Shelar in GRE header. It makes impossible maintaining even soft 134c5441932SPravin B Shelar state for keyed GRE tunnels with enabled checksum. Tell 135c5441932SPravin B Shelar them "thank you". 1361da177e4SLinus Torvalds 1371da177e4SLinus Torvalds Well, I wonder, rfc1812 was written by Cisco employee, 138bff52857Sstephen hemminger what the hell these idiots break standards established 139bff52857Sstephen hemminger by themselves??? 1401da177e4SLinus Torvalds */ 141c5441932SPravin B Shelar struct net *net = dev_net(skb->dev); 142c5441932SPravin B Shelar struct ip_tunnel_net *itn; 14396f5a846SEric Dumazet const struct iphdr *iph; 14488c7664fSArnaldo Carvalho de Melo const int type = icmp_hdr(skb)->type; 14588c7664fSArnaldo Carvalho de Melo const int code = icmp_hdr(skb)->code; 1461da177e4SLinus Torvalds struct ip_tunnel *t; 147d2083287Sstephen hemminger 1481da177e4SLinus Torvalds switch (type) { 1491da177e4SLinus Torvalds default: 1501da177e4SLinus Torvalds case ICMP_PARAMETERPROB: 151bda7bb46SPravin B Shelar return PACKET_RCVD; 1521da177e4SLinus Torvalds 1531da177e4SLinus Torvalds case ICMP_DEST_UNREACH: 1541da177e4SLinus Torvalds switch (code) { 1551da177e4SLinus Torvalds case ICMP_SR_FAILED: 1561da177e4SLinus Torvalds case ICMP_PORT_UNREACH: 1571da177e4SLinus Torvalds /* Impossible event. */ 158bda7bb46SPravin B Shelar return PACKET_RCVD; 1591da177e4SLinus Torvalds default: 1601da177e4SLinus Torvalds /* All others are translated to HOST_UNREACH. 1611da177e4SLinus Torvalds rfc2003 contains "deep thoughts" about NET_UNREACH, 1621da177e4SLinus Torvalds I believe they are just ether pollution. --ANK 1631da177e4SLinus Torvalds */ 1641da177e4SLinus Torvalds break; 1651da177e4SLinus Torvalds } 1661da177e4SLinus Torvalds break; 1671da177e4SLinus Torvalds case ICMP_TIME_EXCEEDED: 1681da177e4SLinus Torvalds if (code != ICMP_EXC_TTL) 169bda7bb46SPravin B Shelar return PACKET_RCVD; 1701da177e4SLinus Torvalds break; 17155be7a9cSDavid S. Miller 17255be7a9cSDavid S. Miller case ICMP_REDIRECT: 17355be7a9cSDavid S. Miller break; 1741da177e4SLinus Torvalds } 1751da177e4SLinus Torvalds 176bda7bb46SPravin B Shelar if (tpi->proto == htons(ETH_P_TEB)) 177c5441932SPravin B Shelar itn = net_generic(net, gre_tap_net_id); 178c5441932SPravin B Shelar else 179c5441932SPravin B Shelar itn = net_generic(net, ipgre_net_id); 180c5441932SPravin B Shelar 181c0c0c50fSDuan Jiong iph = (const struct iphdr *)(icmp_hdr(skb) + 1); 182bda7bb46SPravin B Shelar t = ip_tunnel_lookup(itn, skb->dev->ifindex, tpi->flags, 183bda7bb46SPravin B Shelar iph->daddr, iph->saddr, tpi->key); 184d2083287Sstephen hemminger 18536393395SDavid S. Miller if (t == NULL) 186bda7bb46SPravin B Shelar return PACKET_REJECT; 18736393395SDavid S. Miller 18836393395SDavid S. Miller if (t->parms.iph.daddr == 0 || 189f97c1e0cSJoe Perches ipv4_is_multicast(t->parms.iph.daddr)) 190bda7bb46SPravin B Shelar return PACKET_RCVD; 1911da177e4SLinus Torvalds 1921da177e4SLinus Torvalds if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED) 193bda7bb46SPravin B Shelar return PACKET_RCVD; 1941da177e4SLinus Torvalds 195da6185d8SWei Yongjun if (time_before(jiffies, t->err_time + IPTUNNEL_ERR_TIMEO)) 1961da177e4SLinus Torvalds t->err_count++; 1971da177e4SLinus Torvalds else 1981da177e4SLinus Torvalds t->err_count = 1; 1991da177e4SLinus Torvalds t->err_time = jiffies; 200bda7bb46SPravin B Shelar return PACKET_RCVD; 2011da177e4SLinus Torvalds } 2021da177e4SLinus Torvalds 203bda7bb46SPravin B Shelar static int ipgre_rcv(struct sk_buff *skb, const struct tnl_ptk_info *tpi) 2041da177e4SLinus Torvalds { 205c5441932SPravin B Shelar struct net *net = dev_net(skb->dev); 206c5441932SPravin B Shelar struct ip_tunnel_net *itn; 207b71d1d42SEric Dumazet const struct iphdr *iph; 2081da177e4SLinus Torvalds struct ip_tunnel *tunnel; 2091da177e4SLinus Torvalds 210bda7bb46SPravin B Shelar if (tpi->proto == htons(ETH_P_TEB)) 211c5441932SPravin B Shelar itn = net_generic(net, gre_tap_net_id); 212c5441932SPravin B Shelar else 213c5441932SPravin B Shelar itn = net_generic(net, ipgre_net_id); 214c5441932SPravin B Shelar 215eddc9ec5SArnaldo Carvalho de Melo iph = ip_hdr(skb); 216bda7bb46SPravin B Shelar tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, tpi->flags, 217bda7bb46SPravin B Shelar iph->saddr, iph->daddr, tpi->key); 2181da177e4SLinus Torvalds 219d2083287Sstephen hemminger if (tunnel) { 2200e3da5bbSTimo Teräs skb_pop_mac_header(skb); 221bda7bb46SPravin B Shelar ip_tunnel_rcv(tunnel, skb, tpi, log_ecn_error); 222bda7bb46SPravin B Shelar return PACKET_RCVD; 2231da177e4SLinus Torvalds } 224bda7bb46SPravin B Shelar return PACKET_REJECT; 2251da177e4SLinus Torvalds } 2261da177e4SLinus Torvalds 227c5441932SPravin B Shelar static void __gre_xmit(struct sk_buff *skb, struct net_device *dev, 228c5441932SPravin B Shelar const struct iphdr *tnl_params, 229c5441932SPravin B Shelar __be16 proto) 230c5441932SPravin B Shelar { 231c5441932SPravin B Shelar struct ip_tunnel *tunnel = netdev_priv(dev); 232c5441932SPravin B Shelar struct tnl_ptk_info tpi; 233c5441932SPravin B Shelar 234c5441932SPravin B Shelar tpi.flags = tunnel->parms.o_flags; 235c5441932SPravin B Shelar tpi.proto = proto; 236c5441932SPravin B Shelar tpi.key = tunnel->parms.o_key; 237c5441932SPravin B Shelar if (tunnel->parms.o_flags & TUNNEL_SEQ) 238c5441932SPravin B Shelar tunnel->o_seqno++; 239c5441932SPravin B Shelar tpi.seq = htonl(tunnel->o_seqno); 240cef401deSEric Dumazet 241c5441932SPravin B Shelar /* Push GRE header. */ 2424565e991STom Herbert gre_build_header(skb, &tpi, tunnel->tun_hlen); 2431da177e4SLinus Torvalds 24454bc9bacSTom Herbert skb_set_inner_protocol(skb, tpi.proto); 24554bc9bacSTom Herbert 246bf3d6a8fSNicolas Dichtel ip_tunnel_xmit(skb, dev, tnl_params, tnl_params->protocol); 2471da177e4SLinus Torvalds } 2481da177e4SLinus Torvalds 249c5441932SPravin B Shelar static netdev_tx_t ipgre_xmit(struct sk_buff *skb, 250c5441932SPravin B Shelar struct net_device *dev) 251ee34c1ebSMichal Schmidt { 252c5441932SPravin B Shelar struct ip_tunnel *tunnel = netdev_priv(dev); 253c5441932SPravin B Shelar const struct iphdr *tnl_params; 254ee34c1ebSMichal Schmidt 255c5441932SPravin B Shelar if (dev->header_ops) { 256c5441932SPravin B Shelar /* Need space for new headers */ 257c5441932SPravin B Shelar if (skb_cow_head(skb, dev->needed_headroom - 2582bac7cb3SChen Gang (tunnel->hlen + sizeof(struct iphdr)))) 259c5441932SPravin B Shelar goto free_skb; 260ee34c1ebSMichal Schmidt 261c5441932SPravin B Shelar tnl_params = (const struct iphdr *)skb->data; 262cbb1e85fSDavid S. Miller 263c5441932SPravin B Shelar /* Pull skb since ip_tunnel_xmit() needs skb->data pointing 264c5441932SPravin B Shelar * to gre header. 265c5441932SPravin B Shelar */ 266c5441932SPravin B Shelar skb_pull(skb, tunnel->hlen + sizeof(struct iphdr)); 2678a0033a9STimo Teräs skb_reset_mac_header(skb); 268c5441932SPravin B Shelar } else { 269c5441932SPravin B Shelar if (skb_cow_head(skb, dev->needed_headroom)) 270c5441932SPravin B Shelar goto free_skb; 271c5441932SPravin B Shelar 272c5441932SPravin B Shelar tnl_params = &tunnel->parms.iph; 273ee34c1ebSMichal Schmidt } 274e1a80002SHerbert Xu 2758a0033a9STimo Teräs skb = gre_handle_offloads(skb, !!(tunnel->parms.o_flags&TUNNEL_CSUM)); 2768a0033a9STimo Teräs if (IS_ERR(skb)) 2778a0033a9STimo Teräs goto out; 2788a0033a9STimo Teräs 279c5441932SPravin B Shelar __gre_xmit(skb, dev, tnl_params, skb->protocol); 280c5441932SPravin B Shelar 281c5441932SPravin B Shelar return NETDEV_TX_OK; 282c5441932SPravin B Shelar 283c5441932SPravin B Shelar free_skb: 2843acfa1e7SEric Dumazet kfree_skb(skb); 285c5441932SPravin B Shelar out: 286c5441932SPravin B Shelar dev->stats.tx_dropped++; 287c5441932SPravin B Shelar return NETDEV_TX_OK; 288ee34c1ebSMichal Schmidt } 289ee34c1ebSMichal Schmidt 290c5441932SPravin B Shelar static netdev_tx_t gre_tap_xmit(struct sk_buff *skb, 291c5441932SPravin B Shelar struct net_device *dev) 292c5441932SPravin B Shelar { 293c5441932SPravin B Shelar struct ip_tunnel *tunnel = netdev_priv(dev); 294ee34c1ebSMichal Schmidt 29545f2e997SPravin B Shelar skb = gre_handle_offloads(skb, !!(tunnel->parms.o_flags&TUNNEL_CSUM)); 296c5441932SPravin B Shelar if (IS_ERR(skb)) 297c5441932SPravin B Shelar goto out; 298ee34c1ebSMichal Schmidt 299c5441932SPravin B Shelar if (skb_cow_head(skb, dev->needed_headroom)) 300c5441932SPravin B Shelar goto free_skb; 30142aa9162SHerbert Xu 302c5441932SPravin B Shelar __gre_xmit(skb, dev, &tunnel->parms.iph, htons(ETH_P_TEB)); 30342aa9162SHerbert Xu 304c5441932SPravin B Shelar return NETDEV_TX_OK; 305c5441932SPravin B Shelar 306c5441932SPravin B Shelar free_skb: 3073acfa1e7SEric Dumazet kfree_skb(skb); 308c5441932SPravin B Shelar out: 309c5441932SPravin B Shelar dev->stats.tx_dropped++; 310c5441932SPravin B Shelar return NETDEV_TX_OK; 31168c33163SPravin B Shelar } 312ee34c1ebSMichal Schmidt 313c5441932SPravin B Shelar static int ipgre_tunnel_ioctl(struct net_device *dev, 314c5441932SPravin B Shelar struct ifreq *ifr, int cmd) 3151da177e4SLinus Torvalds { 3164565e991STom Herbert int err; 3171da177e4SLinus Torvalds struct ip_tunnel_parm p; 3181da177e4SLinus Torvalds 3191da177e4SLinus Torvalds if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) 320c5441932SPravin B Shelar return -EFAULT; 3216c734fb8SCong Wang if (cmd == SIOCADDTUNNEL || cmd == SIOCCHGTUNNEL) { 3221da177e4SLinus Torvalds if (p.iph.version != 4 || p.iph.protocol != IPPROTO_GRE || 3231da177e4SLinus Torvalds p.iph.ihl != 5 || (p.iph.frag_off&htons(~IP_DF)) || 3246c734fb8SCong Wang ((p.i_flags|p.o_flags)&(GRE_VERSION|GRE_ROUTING))) 3251da177e4SLinus Torvalds return -EINVAL; 326c5441932SPravin B Shelar } 327c5441932SPravin B Shelar p.i_flags = gre_flags_to_tnl_flags(p.i_flags); 328c5441932SPravin B Shelar p.o_flags = gre_flags_to_tnl_flags(p.o_flags); 329c5441932SPravin B Shelar 330c5441932SPravin B Shelar err = ip_tunnel_ioctl(dev, &p, cmd); 331c5441932SPravin B Shelar if (err) 332c5441932SPravin B Shelar return err; 333c5441932SPravin B Shelar 334c5441932SPravin B Shelar p.i_flags = tnl_flags_to_gre_flags(p.i_flags); 335c5441932SPravin B Shelar p.o_flags = tnl_flags_to_gre_flags(p.o_flags); 336c5441932SPravin B Shelar 337c5441932SPravin B Shelar if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p))) 338c5441932SPravin B Shelar return -EFAULT; 3391da177e4SLinus Torvalds return 0; 3401da177e4SLinus Torvalds } 3411da177e4SLinus Torvalds 3421da177e4SLinus Torvalds /* Nice toy. Unfortunately, useless in real life :-) 3431da177e4SLinus Torvalds It allows to construct virtual multiprotocol broadcast "LAN" 3441da177e4SLinus Torvalds over the Internet, provided multicast routing is tuned. 3451da177e4SLinus Torvalds 3461da177e4SLinus Torvalds 3471da177e4SLinus Torvalds I have no idea was this bicycle invented before me, 3481da177e4SLinus Torvalds so that I had to set ARPHRD_IPGRE to a random value. 3491da177e4SLinus Torvalds I have an impression, that Cisco could make something similar, 3501da177e4SLinus Torvalds but this feature is apparently missing in IOS<=11.2(8). 3511da177e4SLinus Torvalds 3521da177e4SLinus Torvalds I set up 10.66.66/24 and fec0:6666:6666::0/96 as virtual networks 3531da177e4SLinus Torvalds with broadcast 224.66.66.66. If you have access to mbone, play with me :-) 3541da177e4SLinus Torvalds 3551da177e4SLinus Torvalds ping -t 255 224.66.66.66 3561da177e4SLinus Torvalds 3571da177e4SLinus Torvalds If nobody answers, mbone does not work. 3581da177e4SLinus Torvalds 3591da177e4SLinus Torvalds ip tunnel add Universe mode gre remote 224.66.66.66 local <Your_real_addr> ttl 255 3601da177e4SLinus Torvalds ip addr add 10.66.66.<somewhat>/24 dev Universe 3611da177e4SLinus Torvalds ifconfig Universe up 3621da177e4SLinus Torvalds ifconfig Universe add fe80::<Your_real_addr>/10 3631da177e4SLinus Torvalds ifconfig Universe add fec0:6666:6666::<Your_real_addr>/96 3641da177e4SLinus Torvalds ftp 10.66.66.66 3651da177e4SLinus Torvalds ... 3661da177e4SLinus Torvalds ftp fec0:6666:6666::193.233.7.65 3671da177e4SLinus Torvalds ... 3681da177e4SLinus Torvalds */ 3693b04dddeSStephen Hemminger static int ipgre_header(struct sk_buff *skb, struct net_device *dev, 3703b04dddeSStephen Hemminger unsigned short type, 3711507850bSEric Dumazet const void *daddr, const void *saddr, unsigned int len) 3721da177e4SLinus Torvalds { 3732941a486SPatrick McHardy struct ip_tunnel *t = netdev_priv(dev); 374c5441932SPravin B Shelar struct iphdr *iph; 375c5441932SPravin B Shelar struct gre_base_hdr *greh; 376c5441932SPravin B Shelar 377c5441932SPravin B Shelar iph = (struct iphdr *)skb_push(skb, t->hlen + sizeof(*iph)); 378c5441932SPravin B Shelar greh = (struct gre_base_hdr *)(iph+1); 379c5441932SPravin B Shelar greh->flags = tnl_flags_to_gre_flags(t->parms.o_flags); 380c5441932SPravin B Shelar greh->protocol = htons(type); 3811da177e4SLinus Torvalds 3821da177e4SLinus Torvalds memcpy(iph, &t->parms.iph, sizeof(struct iphdr)); 3831da177e4SLinus Torvalds 384c5441932SPravin B Shelar /* Set the source hardware address. */ 3851da177e4SLinus Torvalds if (saddr) 3861da177e4SLinus Torvalds memcpy(&iph->saddr, saddr, 4); 3876d55cb91STimo Teräs if (daddr) 3881da177e4SLinus Torvalds memcpy(&iph->daddr, daddr, 4); 3896d55cb91STimo Teräs if (iph->daddr) 39077a482bdSTimo Teräs return t->hlen + sizeof(*iph); 3911da177e4SLinus Torvalds 392c5441932SPravin B Shelar return -(t->hlen + sizeof(*iph)); 3931da177e4SLinus Torvalds } 3941da177e4SLinus Torvalds 3956a5f44d7STimo Teras static int ipgre_header_parse(const struct sk_buff *skb, unsigned char *haddr) 3966a5f44d7STimo Teras { 397b71d1d42SEric Dumazet const struct iphdr *iph = (const struct iphdr *) skb_mac_header(skb); 3986a5f44d7STimo Teras memcpy(haddr, &iph->saddr, 4); 3996a5f44d7STimo Teras return 4; 4006a5f44d7STimo Teras } 4016a5f44d7STimo Teras 4023b04dddeSStephen Hemminger static const struct header_ops ipgre_header_ops = { 4033b04dddeSStephen Hemminger .create = ipgre_header, 4046a5f44d7STimo Teras .parse = ipgre_header_parse, 4053b04dddeSStephen Hemminger }; 4063b04dddeSStephen Hemminger 4076a5f44d7STimo Teras #ifdef CONFIG_NET_IPGRE_BROADCAST 4081da177e4SLinus Torvalds static int ipgre_open(struct net_device *dev) 4091da177e4SLinus Torvalds { 4102941a486SPatrick McHardy struct ip_tunnel *t = netdev_priv(dev); 4111da177e4SLinus Torvalds 412f97c1e0cSJoe Perches if (ipv4_is_multicast(t->parms.iph.daddr)) { 413cbb1e85fSDavid S. Miller struct flowi4 fl4; 414cbb1e85fSDavid S. Miller struct rtable *rt; 415cbb1e85fSDavid S. Miller 416b57708adSNicolas Dichtel rt = ip_route_output_gre(t->net, &fl4, 41778fbfd8aSDavid S. Miller t->parms.iph.daddr, 41878fbfd8aSDavid S. Miller t->parms.iph.saddr, 41978fbfd8aSDavid S. Miller t->parms.o_key, 42078fbfd8aSDavid S. Miller RT_TOS(t->parms.iph.tos), 42178fbfd8aSDavid S. Miller t->parms.link); 422b23dd4feSDavid S. Miller if (IS_ERR(rt)) 4231da177e4SLinus Torvalds return -EADDRNOTAVAIL; 424d8d1f30bSChangli Gao dev = rt->dst.dev; 4251da177e4SLinus Torvalds ip_rt_put(rt); 426e5ed6399SHerbert Xu if (__in_dev_get_rtnl(dev) == NULL) 4271da177e4SLinus Torvalds return -EADDRNOTAVAIL; 4281da177e4SLinus Torvalds t->mlink = dev->ifindex; 429e5ed6399SHerbert Xu ip_mc_inc_group(__in_dev_get_rtnl(dev), t->parms.iph.daddr); 4301da177e4SLinus Torvalds } 4311da177e4SLinus Torvalds return 0; 4321da177e4SLinus Torvalds } 4331da177e4SLinus Torvalds 4341da177e4SLinus Torvalds static int ipgre_close(struct net_device *dev) 4351da177e4SLinus Torvalds { 4362941a486SPatrick McHardy struct ip_tunnel *t = netdev_priv(dev); 437b8c26a33SStephen Hemminger 438f97c1e0cSJoe Perches if (ipv4_is_multicast(t->parms.iph.daddr) && t->mlink) { 4397fee0ca2SDenis V. Lunev struct in_device *in_dev; 440b57708adSNicolas Dichtel in_dev = inetdev_by_index(t->net, t->mlink); 4418723e1b4SEric Dumazet if (in_dev) 4421da177e4SLinus Torvalds ip_mc_dec_group(in_dev, t->parms.iph.daddr); 4431da177e4SLinus Torvalds } 4441da177e4SLinus Torvalds return 0; 4451da177e4SLinus Torvalds } 4461da177e4SLinus Torvalds #endif 4471da177e4SLinus Torvalds 448b8c26a33SStephen Hemminger static const struct net_device_ops ipgre_netdev_ops = { 449b8c26a33SStephen Hemminger .ndo_init = ipgre_tunnel_init, 450c5441932SPravin B Shelar .ndo_uninit = ip_tunnel_uninit, 451b8c26a33SStephen Hemminger #ifdef CONFIG_NET_IPGRE_BROADCAST 452b8c26a33SStephen Hemminger .ndo_open = ipgre_open, 453b8c26a33SStephen Hemminger .ndo_stop = ipgre_close, 454b8c26a33SStephen Hemminger #endif 455c5441932SPravin B Shelar .ndo_start_xmit = ipgre_xmit, 456b8c26a33SStephen Hemminger .ndo_do_ioctl = ipgre_tunnel_ioctl, 457c5441932SPravin B Shelar .ndo_change_mtu = ip_tunnel_change_mtu, 458c5441932SPravin B Shelar .ndo_get_stats64 = ip_tunnel_get_stats64, 459b8c26a33SStephen Hemminger }; 460b8c26a33SStephen Hemminger 4616b78f16eSEric Dumazet #define GRE_FEATURES (NETIF_F_SG | \ 4626b78f16eSEric Dumazet NETIF_F_FRAGLIST | \ 4636b78f16eSEric Dumazet NETIF_F_HIGHDMA | \ 4646b78f16eSEric Dumazet NETIF_F_HW_CSUM) 4656b78f16eSEric Dumazet 4661da177e4SLinus Torvalds static void ipgre_tunnel_setup(struct net_device *dev) 4671da177e4SLinus Torvalds { 468b8c26a33SStephen Hemminger dev->netdev_ops = &ipgre_netdev_ops; 4695a455275SNicolas Dichtel dev->type = ARPHRD_IPGRE; 470c5441932SPravin B Shelar ip_tunnel_setup(dev, ipgre_net_id); 471c5441932SPravin B Shelar } 4721da177e4SLinus Torvalds 473c5441932SPravin B Shelar static void __gre_tunnel_init(struct net_device *dev) 474c5441932SPravin B Shelar { 475c5441932SPravin B Shelar struct ip_tunnel *tunnel; 4764565e991STom Herbert int t_hlen; 477c5441932SPravin B Shelar 478c5441932SPravin B Shelar tunnel = netdev_priv(dev); 4794565e991STom Herbert tunnel->tun_hlen = ip_gre_calc_hlen(tunnel->parms.o_flags); 480c5441932SPravin B Shelar tunnel->parms.iph.protocol = IPPROTO_GRE; 481c5441932SPravin B Shelar 4824565e991STom Herbert tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen; 4834565e991STom Herbert 4844565e991STom Herbert t_hlen = tunnel->hlen + sizeof(struct iphdr); 4854565e991STom Herbert 4864565e991STom Herbert dev->needed_headroom = LL_MAX_HEADER + t_hlen + 4; 4874565e991STom Herbert dev->mtu = ETH_DATA_LEN - t_hlen - 4; 4886b78f16eSEric Dumazet 489b57708adSNicolas Dichtel dev->features |= GRE_FEATURES; 4906b78f16eSEric Dumazet dev->hw_features |= GRE_FEATURES; 491c5441932SPravin B Shelar 492c5441932SPravin B Shelar if (!(tunnel->parms.o_flags & TUNNEL_SEQ)) { 493c5441932SPravin B Shelar /* TCP offload with GRE SEQ is not supported. */ 494c5441932SPravin B Shelar dev->features |= NETIF_F_GSO_SOFTWARE; 495c5441932SPravin B Shelar dev->hw_features |= NETIF_F_GSO_SOFTWARE; 496c5441932SPravin B Shelar /* Can use a lockless transmit, unless we generate 497c5441932SPravin B Shelar * output sequences 498c5441932SPravin B Shelar */ 499c5441932SPravin B Shelar dev->features |= NETIF_F_LLTX; 500c5441932SPravin B Shelar } 5011da177e4SLinus Torvalds } 5021da177e4SLinus Torvalds 5031da177e4SLinus Torvalds static int ipgre_tunnel_init(struct net_device *dev) 5041da177e4SLinus Torvalds { 505c5441932SPravin B Shelar struct ip_tunnel *tunnel = netdev_priv(dev); 506c5441932SPravin B Shelar struct iphdr *iph = &tunnel->parms.iph; 5071da177e4SLinus Torvalds 508c5441932SPravin B Shelar __gre_tunnel_init(dev); 5091da177e4SLinus Torvalds 510c5441932SPravin B Shelar memcpy(dev->dev_addr, &iph->saddr, 4); 511c5441932SPravin B Shelar memcpy(dev->broadcast, &iph->daddr, 4); 5121da177e4SLinus Torvalds 513c5441932SPravin B Shelar dev->flags = IFF_NOARP; 51402875878SEric Dumazet netif_keep_dst(dev); 515c5441932SPravin B Shelar dev->addr_len = 4; 5161da177e4SLinus Torvalds 5171da177e4SLinus Torvalds if (iph->daddr) { 5181da177e4SLinus Torvalds #ifdef CONFIG_NET_IPGRE_BROADCAST 519f97c1e0cSJoe Perches if (ipv4_is_multicast(iph->daddr)) { 5201da177e4SLinus Torvalds if (!iph->saddr) 5211da177e4SLinus Torvalds return -EINVAL; 5221da177e4SLinus Torvalds dev->flags = IFF_BROADCAST; 5233b04dddeSStephen Hemminger dev->header_ops = &ipgre_header_ops; 5241da177e4SLinus Torvalds } 5251da177e4SLinus Torvalds #endif 526ee34c1ebSMichal Schmidt } else 5276a5f44d7STimo Teras dev->header_ops = &ipgre_header_ops; 5281da177e4SLinus Torvalds 529c5441932SPravin B Shelar return ip_tunnel_init(dev); 53060769a5dSEric Dumazet } 53160769a5dSEric Dumazet 532bda7bb46SPravin B Shelar static struct gre_cisco_protocol ipgre_protocol = { 5331da177e4SLinus Torvalds .handler = ipgre_rcv, 5341da177e4SLinus Torvalds .err_handler = ipgre_err, 535bda7bb46SPravin B Shelar .priority = 0, 5361da177e4SLinus Torvalds }; 5371da177e4SLinus Torvalds 5382c8c1e72SAlexey Dobriyan static int __net_init ipgre_init_net(struct net *net) 53959a4c759SPavel Emelyanov { 540c5441932SPravin B Shelar return ip_tunnel_init_net(net, ipgre_net_id, &ipgre_link_ops, NULL); 54159a4c759SPavel Emelyanov } 54259a4c759SPavel Emelyanov 5432c8c1e72SAlexey Dobriyan static void __net_exit ipgre_exit_net(struct net *net) 54459a4c759SPavel Emelyanov { 545c5441932SPravin B Shelar struct ip_tunnel_net *itn = net_generic(net, ipgre_net_id); 5466c742e71SNicolas Dichtel ip_tunnel_delete_net(itn, &ipgre_link_ops); 54759a4c759SPavel Emelyanov } 54859a4c759SPavel Emelyanov 54959a4c759SPavel Emelyanov static struct pernet_operations ipgre_net_ops = { 55059a4c759SPavel Emelyanov .init = ipgre_init_net, 55159a4c759SPavel Emelyanov .exit = ipgre_exit_net, 552cfb8fbf2SEric W. Biederman .id = &ipgre_net_id, 553c5441932SPravin B Shelar .size = sizeof(struct ip_tunnel_net), 55459a4c759SPavel Emelyanov }; 5551da177e4SLinus Torvalds 556c19e654dSHerbert Xu static int ipgre_tunnel_validate(struct nlattr *tb[], struct nlattr *data[]) 557c19e654dSHerbert Xu { 558c19e654dSHerbert Xu __be16 flags; 559c19e654dSHerbert Xu 560c19e654dSHerbert Xu if (!data) 561c19e654dSHerbert Xu return 0; 562c19e654dSHerbert Xu 563c19e654dSHerbert Xu flags = 0; 564c19e654dSHerbert Xu if (data[IFLA_GRE_IFLAGS]) 565c19e654dSHerbert Xu flags |= nla_get_be16(data[IFLA_GRE_IFLAGS]); 566c19e654dSHerbert Xu if (data[IFLA_GRE_OFLAGS]) 567c19e654dSHerbert Xu flags |= nla_get_be16(data[IFLA_GRE_OFLAGS]); 568c19e654dSHerbert Xu if (flags & (GRE_VERSION|GRE_ROUTING)) 569c19e654dSHerbert Xu return -EINVAL; 570c19e654dSHerbert Xu 571c19e654dSHerbert Xu return 0; 572c19e654dSHerbert Xu } 573c19e654dSHerbert Xu 574e1a80002SHerbert Xu static int ipgre_tap_validate(struct nlattr *tb[], struct nlattr *data[]) 575e1a80002SHerbert Xu { 576e1a80002SHerbert Xu __be32 daddr; 577e1a80002SHerbert Xu 578e1a80002SHerbert Xu if (tb[IFLA_ADDRESS]) { 579e1a80002SHerbert Xu if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN) 580e1a80002SHerbert Xu return -EINVAL; 581e1a80002SHerbert Xu if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS]))) 582e1a80002SHerbert Xu return -EADDRNOTAVAIL; 583e1a80002SHerbert Xu } 584e1a80002SHerbert Xu 585e1a80002SHerbert Xu if (!data) 586e1a80002SHerbert Xu goto out; 587e1a80002SHerbert Xu 588e1a80002SHerbert Xu if (data[IFLA_GRE_REMOTE]) { 589e1a80002SHerbert Xu memcpy(&daddr, nla_data(data[IFLA_GRE_REMOTE]), 4); 590e1a80002SHerbert Xu if (!daddr) 591e1a80002SHerbert Xu return -EINVAL; 592e1a80002SHerbert Xu } 593e1a80002SHerbert Xu 594e1a80002SHerbert Xu out: 595e1a80002SHerbert Xu return ipgre_tunnel_validate(tb, data); 596e1a80002SHerbert Xu } 597e1a80002SHerbert Xu 598c5441932SPravin B Shelar static void ipgre_netlink_parms(struct nlattr *data[], struct nlattr *tb[], 599c19e654dSHerbert Xu struct ip_tunnel_parm *parms) 600c19e654dSHerbert Xu { 6017bb82d92SHerbert Xu memset(parms, 0, sizeof(*parms)); 602c19e654dSHerbert Xu 603c19e654dSHerbert Xu parms->iph.protocol = IPPROTO_GRE; 604c19e654dSHerbert Xu 605c19e654dSHerbert Xu if (!data) 606c19e654dSHerbert Xu return; 607c19e654dSHerbert Xu 608c19e654dSHerbert Xu if (data[IFLA_GRE_LINK]) 609c19e654dSHerbert Xu parms->link = nla_get_u32(data[IFLA_GRE_LINK]); 610c19e654dSHerbert Xu 611c19e654dSHerbert Xu if (data[IFLA_GRE_IFLAGS]) 612c5441932SPravin B Shelar parms->i_flags = gre_flags_to_tnl_flags(nla_get_be16(data[IFLA_GRE_IFLAGS])); 613c19e654dSHerbert Xu 614c19e654dSHerbert Xu if (data[IFLA_GRE_OFLAGS]) 615c5441932SPravin B Shelar parms->o_flags = gre_flags_to_tnl_flags(nla_get_be16(data[IFLA_GRE_OFLAGS])); 616c19e654dSHerbert Xu 617c19e654dSHerbert Xu if (data[IFLA_GRE_IKEY]) 618c19e654dSHerbert Xu parms->i_key = nla_get_be32(data[IFLA_GRE_IKEY]); 619c19e654dSHerbert Xu 620c19e654dSHerbert Xu if (data[IFLA_GRE_OKEY]) 621c19e654dSHerbert Xu parms->o_key = nla_get_be32(data[IFLA_GRE_OKEY]); 622c19e654dSHerbert Xu 623c19e654dSHerbert Xu if (data[IFLA_GRE_LOCAL]) 624*67b61f6cSJiri Benc parms->iph.saddr = nla_get_in_addr(data[IFLA_GRE_LOCAL]); 625c19e654dSHerbert Xu 626c19e654dSHerbert Xu if (data[IFLA_GRE_REMOTE]) 627*67b61f6cSJiri Benc parms->iph.daddr = nla_get_in_addr(data[IFLA_GRE_REMOTE]); 628c19e654dSHerbert Xu 629c19e654dSHerbert Xu if (data[IFLA_GRE_TTL]) 630c19e654dSHerbert Xu parms->iph.ttl = nla_get_u8(data[IFLA_GRE_TTL]); 631c19e654dSHerbert Xu 632c19e654dSHerbert Xu if (data[IFLA_GRE_TOS]) 633c19e654dSHerbert Xu parms->iph.tos = nla_get_u8(data[IFLA_GRE_TOS]); 634c19e654dSHerbert Xu 635c19e654dSHerbert Xu if (!data[IFLA_GRE_PMTUDISC] || nla_get_u8(data[IFLA_GRE_PMTUDISC])) 636c19e654dSHerbert Xu parms->iph.frag_off = htons(IP_DF); 637c19e654dSHerbert Xu } 638c19e654dSHerbert Xu 6394565e991STom Herbert /* This function returns true when ENCAP attributes are present in the nl msg */ 6404565e991STom Herbert static bool ipgre_netlink_encap_parms(struct nlattr *data[], 6414565e991STom Herbert struct ip_tunnel_encap *ipencap) 6424565e991STom Herbert { 6434565e991STom Herbert bool ret = false; 6444565e991STom Herbert 6454565e991STom Herbert memset(ipencap, 0, sizeof(*ipencap)); 6464565e991STom Herbert 6474565e991STom Herbert if (!data) 6484565e991STom Herbert return ret; 6494565e991STom Herbert 6504565e991STom Herbert if (data[IFLA_GRE_ENCAP_TYPE]) { 6514565e991STom Herbert ret = true; 6524565e991STom Herbert ipencap->type = nla_get_u16(data[IFLA_GRE_ENCAP_TYPE]); 6534565e991STom Herbert } 6544565e991STom Herbert 6554565e991STom Herbert if (data[IFLA_GRE_ENCAP_FLAGS]) { 6564565e991STom Herbert ret = true; 6574565e991STom Herbert ipencap->flags = nla_get_u16(data[IFLA_GRE_ENCAP_FLAGS]); 6584565e991STom Herbert } 6594565e991STom Herbert 6604565e991STom Herbert if (data[IFLA_GRE_ENCAP_SPORT]) { 6614565e991STom Herbert ret = true; 6623e97fa70SSabrina Dubroca ipencap->sport = nla_get_be16(data[IFLA_GRE_ENCAP_SPORT]); 6634565e991STom Herbert } 6644565e991STom Herbert 6654565e991STom Herbert if (data[IFLA_GRE_ENCAP_DPORT]) { 6664565e991STom Herbert ret = true; 6673e97fa70SSabrina Dubroca ipencap->dport = nla_get_be16(data[IFLA_GRE_ENCAP_DPORT]); 6684565e991STom Herbert } 6694565e991STom Herbert 6704565e991STom Herbert return ret; 6714565e991STom Herbert } 6724565e991STom Herbert 673c5441932SPravin B Shelar static int gre_tap_init(struct net_device *dev) 674e1a80002SHerbert Xu { 675c5441932SPravin B Shelar __gre_tunnel_init(dev); 676bec94d43Sstephen hemminger dev->priv_flags |= IFF_LIVE_ADDR_CHANGE; 677e1a80002SHerbert Xu 678c5441932SPravin B Shelar return ip_tunnel_init(dev); 679e1a80002SHerbert Xu } 680e1a80002SHerbert Xu 681c5441932SPravin B Shelar static const struct net_device_ops gre_tap_netdev_ops = { 682c5441932SPravin B Shelar .ndo_init = gre_tap_init, 683c5441932SPravin B Shelar .ndo_uninit = ip_tunnel_uninit, 684c5441932SPravin B Shelar .ndo_start_xmit = gre_tap_xmit, 685b8c26a33SStephen Hemminger .ndo_set_mac_address = eth_mac_addr, 686b8c26a33SStephen Hemminger .ndo_validate_addr = eth_validate_addr, 687c5441932SPravin B Shelar .ndo_change_mtu = ip_tunnel_change_mtu, 688c5441932SPravin B Shelar .ndo_get_stats64 = ip_tunnel_get_stats64, 689b8c26a33SStephen Hemminger }; 690b8c26a33SStephen Hemminger 691e1a80002SHerbert Xu static void ipgre_tap_setup(struct net_device *dev) 692e1a80002SHerbert Xu { 693e1a80002SHerbert Xu ether_setup(dev); 694c5441932SPravin B Shelar dev->netdev_ops = &gre_tap_netdev_ops; 695f8c1b7ceSstephen hemminger dev->priv_flags |= IFF_LIVE_ADDR_CHANGE; 696c5441932SPravin B Shelar ip_tunnel_setup(dev, gre_tap_net_id); 697e1a80002SHerbert Xu } 698e1a80002SHerbert Xu 699c5441932SPravin B Shelar static int ipgre_newlink(struct net *src_net, struct net_device *dev, 700c5441932SPravin B Shelar struct nlattr *tb[], struct nlattr *data[]) 701c19e654dSHerbert Xu { 702c5441932SPravin B Shelar struct ip_tunnel_parm p; 7034565e991STom Herbert struct ip_tunnel_encap ipencap; 7044565e991STom Herbert 7054565e991STom Herbert if (ipgre_netlink_encap_parms(data, &ipencap)) { 7064565e991STom Herbert struct ip_tunnel *t = netdev_priv(dev); 7074565e991STom Herbert int err = ip_tunnel_encap_setup(t, &ipencap); 7084565e991STom Herbert 7094565e991STom Herbert if (err < 0) 7104565e991STom Herbert return err; 7114565e991STom Herbert } 712c19e654dSHerbert Xu 713c5441932SPravin B Shelar ipgre_netlink_parms(data, tb, &p); 714c5441932SPravin B Shelar return ip_tunnel_newlink(dev, tb, &p); 715c19e654dSHerbert Xu } 716c19e654dSHerbert Xu 717c19e654dSHerbert Xu static int ipgre_changelink(struct net_device *dev, struct nlattr *tb[], 718c19e654dSHerbert Xu struct nlattr *data[]) 719c19e654dSHerbert Xu { 720c19e654dSHerbert Xu struct ip_tunnel_parm p; 7214565e991STom Herbert struct ip_tunnel_encap ipencap; 7224565e991STom Herbert 7234565e991STom Herbert if (ipgre_netlink_encap_parms(data, &ipencap)) { 7244565e991STom Herbert struct ip_tunnel *t = netdev_priv(dev); 7254565e991STom Herbert int err = ip_tunnel_encap_setup(t, &ipencap); 7264565e991STom Herbert 7274565e991STom Herbert if (err < 0) 7284565e991STom Herbert return err; 7294565e991STom Herbert } 730c19e654dSHerbert Xu 731c5441932SPravin B Shelar ipgre_netlink_parms(data, tb, &p); 732c5441932SPravin B Shelar return ip_tunnel_changelink(dev, tb, &p); 733c19e654dSHerbert Xu } 734c19e654dSHerbert Xu 735c19e654dSHerbert Xu static size_t ipgre_get_size(const struct net_device *dev) 736c19e654dSHerbert Xu { 737c19e654dSHerbert Xu return 738c19e654dSHerbert Xu /* IFLA_GRE_LINK */ 739c19e654dSHerbert Xu nla_total_size(4) + 740c19e654dSHerbert Xu /* IFLA_GRE_IFLAGS */ 741c19e654dSHerbert Xu nla_total_size(2) + 742c19e654dSHerbert Xu /* IFLA_GRE_OFLAGS */ 743c19e654dSHerbert Xu nla_total_size(2) + 744c19e654dSHerbert Xu /* IFLA_GRE_IKEY */ 745c19e654dSHerbert Xu nla_total_size(4) + 746c19e654dSHerbert Xu /* IFLA_GRE_OKEY */ 747c19e654dSHerbert Xu nla_total_size(4) + 748c19e654dSHerbert Xu /* IFLA_GRE_LOCAL */ 749c19e654dSHerbert Xu nla_total_size(4) + 750c19e654dSHerbert Xu /* IFLA_GRE_REMOTE */ 751c19e654dSHerbert Xu nla_total_size(4) + 752c19e654dSHerbert Xu /* IFLA_GRE_TTL */ 753c19e654dSHerbert Xu nla_total_size(1) + 754c19e654dSHerbert Xu /* IFLA_GRE_TOS */ 755c19e654dSHerbert Xu nla_total_size(1) + 756c19e654dSHerbert Xu /* IFLA_GRE_PMTUDISC */ 757c19e654dSHerbert Xu nla_total_size(1) + 7584565e991STom Herbert /* IFLA_GRE_ENCAP_TYPE */ 7594565e991STom Herbert nla_total_size(2) + 7604565e991STom Herbert /* IFLA_GRE_ENCAP_FLAGS */ 7614565e991STom Herbert nla_total_size(2) + 7624565e991STom Herbert /* IFLA_GRE_ENCAP_SPORT */ 7634565e991STom Herbert nla_total_size(2) + 7644565e991STom Herbert /* IFLA_GRE_ENCAP_DPORT */ 7654565e991STom Herbert nla_total_size(2) + 766c19e654dSHerbert Xu 0; 767c19e654dSHerbert Xu } 768c19e654dSHerbert Xu 769c19e654dSHerbert Xu static int ipgre_fill_info(struct sk_buff *skb, const struct net_device *dev) 770c19e654dSHerbert Xu { 771c19e654dSHerbert Xu struct ip_tunnel *t = netdev_priv(dev); 772c19e654dSHerbert Xu struct ip_tunnel_parm *p = &t->parms; 773c19e654dSHerbert Xu 774f3756b79SDavid S. Miller if (nla_put_u32(skb, IFLA_GRE_LINK, p->link) || 775c5441932SPravin B Shelar nla_put_be16(skb, IFLA_GRE_IFLAGS, tnl_flags_to_gre_flags(p->i_flags)) || 776c5441932SPravin B Shelar nla_put_be16(skb, IFLA_GRE_OFLAGS, tnl_flags_to_gre_flags(p->o_flags)) || 777f3756b79SDavid S. Miller nla_put_be32(skb, IFLA_GRE_IKEY, p->i_key) || 778f3756b79SDavid S. Miller nla_put_be32(skb, IFLA_GRE_OKEY, p->o_key) || 779930345eaSJiri Benc nla_put_in_addr(skb, IFLA_GRE_LOCAL, p->iph.saddr) || 780930345eaSJiri Benc nla_put_in_addr(skb, IFLA_GRE_REMOTE, p->iph.daddr) || 781f3756b79SDavid S. Miller nla_put_u8(skb, IFLA_GRE_TTL, p->iph.ttl) || 782f3756b79SDavid S. Miller nla_put_u8(skb, IFLA_GRE_TOS, p->iph.tos) || 783f3756b79SDavid S. Miller nla_put_u8(skb, IFLA_GRE_PMTUDISC, 784f3756b79SDavid S. Miller !!(p->iph.frag_off & htons(IP_DF)))) 785f3756b79SDavid S. Miller goto nla_put_failure; 7864565e991STom Herbert 7874565e991STom Herbert if (nla_put_u16(skb, IFLA_GRE_ENCAP_TYPE, 7884565e991STom Herbert t->encap.type) || 7893e97fa70SSabrina Dubroca nla_put_be16(skb, IFLA_GRE_ENCAP_SPORT, 7904565e991STom Herbert t->encap.sport) || 7913e97fa70SSabrina Dubroca nla_put_be16(skb, IFLA_GRE_ENCAP_DPORT, 7924565e991STom Herbert t->encap.dport) || 7934565e991STom Herbert nla_put_u16(skb, IFLA_GRE_ENCAP_FLAGS, 794e1b2cb65STom Herbert t->encap.flags)) 7954565e991STom Herbert goto nla_put_failure; 7964565e991STom Herbert 797c19e654dSHerbert Xu return 0; 798c19e654dSHerbert Xu 799c19e654dSHerbert Xu nla_put_failure: 800c19e654dSHerbert Xu return -EMSGSIZE; 801c19e654dSHerbert Xu } 802c19e654dSHerbert Xu 803c19e654dSHerbert Xu static const struct nla_policy ipgre_policy[IFLA_GRE_MAX + 1] = { 804c19e654dSHerbert Xu [IFLA_GRE_LINK] = { .type = NLA_U32 }, 805c19e654dSHerbert Xu [IFLA_GRE_IFLAGS] = { .type = NLA_U16 }, 806c19e654dSHerbert Xu [IFLA_GRE_OFLAGS] = { .type = NLA_U16 }, 807c19e654dSHerbert Xu [IFLA_GRE_IKEY] = { .type = NLA_U32 }, 808c19e654dSHerbert Xu [IFLA_GRE_OKEY] = { .type = NLA_U32 }, 8094d74f8baSPatrick McHardy [IFLA_GRE_LOCAL] = { .len = FIELD_SIZEOF(struct iphdr, saddr) }, 8104d74f8baSPatrick McHardy [IFLA_GRE_REMOTE] = { .len = FIELD_SIZEOF(struct iphdr, daddr) }, 811c19e654dSHerbert Xu [IFLA_GRE_TTL] = { .type = NLA_U8 }, 812c19e654dSHerbert Xu [IFLA_GRE_TOS] = { .type = NLA_U8 }, 813c19e654dSHerbert Xu [IFLA_GRE_PMTUDISC] = { .type = NLA_U8 }, 8144565e991STom Herbert [IFLA_GRE_ENCAP_TYPE] = { .type = NLA_U16 }, 8154565e991STom Herbert [IFLA_GRE_ENCAP_FLAGS] = { .type = NLA_U16 }, 8164565e991STom Herbert [IFLA_GRE_ENCAP_SPORT] = { .type = NLA_U16 }, 8174565e991STom Herbert [IFLA_GRE_ENCAP_DPORT] = { .type = NLA_U16 }, 818c19e654dSHerbert Xu }; 819c19e654dSHerbert Xu 820c19e654dSHerbert Xu static struct rtnl_link_ops ipgre_link_ops __read_mostly = { 821c19e654dSHerbert Xu .kind = "gre", 822c19e654dSHerbert Xu .maxtype = IFLA_GRE_MAX, 823c19e654dSHerbert Xu .policy = ipgre_policy, 824c19e654dSHerbert Xu .priv_size = sizeof(struct ip_tunnel), 825c19e654dSHerbert Xu .setup = ipgre_tunnel_setup, 826c19e654dSHerbert Xu .validate = ipgre_tunnel_validate, 827c19e654dSHerbert Xu .newlink = ipgre_newlink, 828c19e654dSHerbert Xu .changelink = ipgre_changelink, 829c5441932SPravin B Shelar .dellink = ip_tunnel_dellink, 830c19e654dSHerbert Xu .get_size = ipgre_get_size, 831c19e654dSHerbert Xu .fill_info = ipgre_fill_info, 8321728d4faSNicolas Dichtel .get_link_net = ip_tunnel_get_link_net, 833c19e654dSHerbert Xu }; 834c19e654dSHerbert Xu 835e1a80002SHerbert Xu static struct rtnl_link_ops ipgre_tap_ops __read_mostly = { 836e1a80002SHerbert Xu .kind = "gretap", 837e1a80002SHerbert Xu .maxtype = IFLA_GRE_MAX, 838e1a80002SHerbert Xu .policy = ipgre_policy, 839e1a80002SHerbert Xu .priv_size = sizeof(struct ip_tunnel), 840e1a80002SHerbert Xu .setup = ipgre_tap_setup, 841e1a80002SHerbert Xu .validate = ipgre_tap_validate, 842e1a80002SHerbert Xu .newlink = ipgre_newlink, 843e1a80002SHerbert Xu .changelink = ipgre_changelink, 844c5441932SPravin B Shelar .dellink = ip_tunnel_dellink, 845e1a80002SHerbert Xu .get_size = ipgre_get_size, 846e1a80002SHerbert Xu .fill_info = ipgre_fill_info, 8471728d4faSNicolas Dichtel .get_link_net = ip_tunnel_get_link_net, 848e1a80002SHerbert Xu }; 849e1a80002SHerbert Xu 850c5441932SPravin B Shelar static int __net_init ipgre_tap_init_net(struct net *net) 851c5441932SPravin B Shelar { 852c5441932SPravin B Shelar return ip_tunnel_init_net(net, gre_tap_net_id, &ipgre_tap_ops, NULL); 853c5441932SPravin B Shelar } 854c5441932SPravin B Shelar 855c5441932SPravin B Shelar static void __net_exit ipgre_tap_exit_net(struct net *net) 856c5441932SPravin B Shelar { 857c5441932SPravin B Shelar struct ip_tunnel_net *itn = net_generic(net, gre_tap_net_id); 8586c742e71SNicolas Dichtel ip_tunnel_delete_net(itn, &ipgre_tap_ops); 859c5441932SPravin B Shelar } 860c5441932SPravin B Shelar 861c5441932SPravin B Shelar static struct pernet_operations ipgre_tap_net_ops = { 862c5441932SPravin B Shelar .init = ipgre_tap_init_net, 863c5441932SPravin B Shelar .exit = ipgre_tap_exit_net, 864c5441932SPravin B Shelar .id = &gre_tap_net_id, 865c5441932SPravin B Shelar .size = sizeof(struct ip_tunnel_net), 866c5441932SPravin B Shelar }; 8671da177e4SLinus Torvalds 8681da177e4SLinus Torvalds static int __init ipgre_init(void) 8691da177e4SLinus Torvalds { 8701da177e4SLinus Torvalds int err; 8711da177e4SLinus Torvalds 872058bd4d2SJoe Perches pr_info("GRE over IPv4 tunneling driver\n"); 8731da177e4SLinus Torvalds 874cfb8fbf2SEric W. Biederman err = register_pernet_device(&ipgre_net_ops); 87559a4c759SPavel Emelyanov if (err < 0) 876c2892f02SAlexey Dobriyan return err; 877c2892f02SAlexey Dobriyan 878c5441932SPravin B Shelar err = register_pernet_device(&ipgre_tap_net_ops); 879c5441932SPravin B Shelar if (err < 0) 880c5441932SPravin B Shelar goto pnet_tap_faied; 881c5441932SPravin B Shelar 882bda7bb46SPravin B Shelar err = gre_cisco_register(&ipgre_protocol); 883c2892f02SAlexey Dobriyan if (err < 0) { 884058bd4d2SJoe Perches pr_info("%s: can't add protocol\n", __func__); 885c2892f02SAlexey Dobriyan goto add_proto_failed; 886c2892f02SAlexey Dobriyan } 8877daa0004SPavel Emelyanov 888c19e654dSHerbert Xu err = rtnl_link_register(&ipgre_link_ops); 889c19e654dSHerbert Xu if (err < 0) 890c19e654dSHerbert Xu goto rtnl_link_failed; 891c19e654dSHerbert Xu 892e1a80002SHerbert Xu err = rtnl_link_register(&ipgre_tap_ops); 893e1a80002SHerbert Xu if (err < 0) 894e1a80002SHerbert Xu goto tap_ops_failed; 895e1a80002SHerbert Xu 896c5441932SPravin B Shelar return 0; 897c19e654dSHerbert Xu 898e1a80002SHerbert Xu tap_ops_failed: 899e1a80002SHerbert Xu rtnl_link_unregister(&ipgre_link_ops); 900c19e654dSHerbert Xu rtnl_link_failed: 901bda7bb46SPravin B Shelar gre_cisco_unregister(&ipgre_protocol); 902c2892f02SAlexey Dobriyan add_proto_failed: 903c5441932SPravin B Shelar unregister_pernet_device(&ipgre_tap_net_ops); 904c5441932SPravin B Shelar pnet_tap_faied: 905c2892f02SAlexey Dobriyan unregister_pernet_device(&ipgre_net_ops); 906c5441932SPravin B Shelar return err; 9071da177e4SLinus Torvalds } 9081da177e4SLinus Torvalds 909db44575fSAlexey Kuznetsov static void __exit ipgre_fini(void) 9101da177e4SLinus Torvalds { 911e1a80002SHerbert Xu rtnl_link_unregister(&ipgre_tap_ops); 912c19e654dSHerbert Xu rtnl_link_unregister(&ipgre_link_ops); 913bda7bb46SPravin B Shelar gre_cisco_unregister(&ipgre_protocol); 914c5441932SPravin B Shelar unregister_pernet_device(&ipgre_tap_net_ops); 915c2892f02SAlexey Dobriyan unregister_pernet_device(&ipgre_net_ops); 9161da177e4SLinus Torvalds } 9171da177e4SLinus Torvalds 9181da177e4SLinus Torvalds module_init(ipgre_init); 9191da177e4SLinus Torvalds module_exit(ipgre_fini); 9201da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 9214d74f8baSPatrick McHardy MODULE_ALIAS_RTNL_LINK("gre"); 9224d74f8baSPatrick McHardy MODULE_ALIAS_RTNL_LINK("gretap"); 9238909c9adSVasiliy Kulikov MODULE_ALIAS_NETDEV("gre0"); 924c5441932SPravin B Shelar MODULE_ALIAS_NETDEV("gretap0"); 925