12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 21da177e4SLinus Torvalds /* 31da177e4SLinus Torvalds * Linux NET3: IP/IP protocol decoder. 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * Authors: 61da177e4SLinus Torvalds * Sam Lantinga (slouken@cs.ucdavis.edu) 02/01/95 71da177e4SLinus Torvalds * 81da177e4SLinus Torvalds * Fixes: 91da177e4SLinus Torvalds * Alan Cox : Merged and made usable non modular (its so tiny its silly as 101da177e4SLinus Torvalds * a module taking up 2 pages). 111da177e4SLinus Torvalds * Alan Cox : Fixed bug with 1.3.18 and IPIP not working (now needs to set skb->h.iph) 121da177e4SLinus Torvalds * to keep ip_forward happy. 131da177e4SLinus Torvalds * Alan Cox : More fixes for 1.3.21, and firewall fix. Maybe this will work soon 8). 141da177e4SLinus Torvalds * Kai Schulte : Fixed #defines for IP_FIREWALL->FIREWALL 151da177e4SLinus Torvalds * David Woodhouse : Perform some basic ICMP handling. 161da177e4SLinus Torvalds * IPIP Routing without decapsulation. 171da177e4SLinus Torvalds * Carlos Picoto : GRE over IP support 181da177e4SLinus Torvalds * Alexey Kuznetsov: Reworked. Really, now it is truncated version of ipv4/ip_gre.c. 191da177e4SLinus Torvalds * I do not want to merge them together. 201da177e4SLinus Torvalds */ 211da177e4SLinus Torvalds 221da177e4SLinus Torvalds /* tunnel.c: an IP tunnel driver 231da177e4SLinus Torvalds 241da177e4SLinus Torvalds The purpose of this driver is to provide an IP tunnel through 251da177e4SLinus Torvalds which you can tunnel network traffic transparently across subnets. 261da177e4SLinus Torvalds 271da177e4SLinus Torvalds This was written by looking at Nick Holloway's dummy driver 281da177e4SLinus Torvalds Thanks for the great code! 291da177e4SLinus Torvalds 301da177e4SLinus Torvalds -Sam Lantinga (slouken@cs.ucdavis.edu) 02/01/95 311da177e4SLinus Torvalds 321da177e4SLinus Torvalds Minor tweaks: 331da177e4SLinus Torvalds Cleaned up the code a little and added some pre-1.3.0 tweaks. 341da177e4SLinus Torvalds dev->hard_header/hard_header_len changed to use no headers. 351da177e4SLinus Torvalds Comments/bracketing tweaked. 361da177e4SLinus Torvalds Made the tunnels use dev->name not tunnel: when error reporting. 371da177e4SLinus Torvalds Added tx_dropped stat 381da177e4SLinus Torvalds 39113aa838SAlan Cox -Alan Cox (alan@lxorguk.ukuu.org.uk) 21 March 95 401da177e4SLinus Torvalds 411da177e4SLinus Torvalds Reworked: 421da177e4SLinus Torvalds Changed to tunnel to destination gateway in addition to the 431da177e4SLinus Torvalds tunnel's pointopoint address 441da177e4SLinus Torvalds Almost completely rewritten 451da177e4SLinus Torvalds Note: There is currently no firewall or ICMP handling done. 461da177e4SLinus Torvalds 471da177e4SLinus Torvalds -Sam Lantinga (slouken@cs.ucdavis.edu) 02/13/96 481da177e4SLinus Torvalds 491da177e4SLinus Torvalds */ 501da177e4SLinus Torvalds 511da177e4SLinus Torvalds /* Things I wish I had known when writing the tunnel driver: 521da177e4SLinus Torvalds 531da177e4SLinus Torvalds When the tunnel_xmit() function is called, the skb contains the 541da177e4SLinus Torvalds packet to be sent (plus a great deal of extra info), and dev 551da177e4SLinus Torvalds contains the tunnel device that _we_ are. 561da177e4SLinus Torvalds 571da177e4SLinus Torvalds When we are passed a packet, we are expected to fill in the 581da177e4SLinus Torvalds source address with our source IP address. 591da177e4SLinus Torvalds 601da177e4SLinus Torvalds What is the proper way to allocate, copy and free a buffer? 611da177e4SLinus Torvalds After you allocate it, it is a "0 length" chunk of memory 621da177e4SLinus Torvalds starting at zero. If you want to add headers to the buffer 631da177e4SLinus Torvalds later, you'll have to call "skb_reserve(skb, amount)" with 641da177e4SLinus Torvalds the amount of memory you want reserved. Then, you call 651da177e4SLinus Torvalds "skb_put(skb, amount)" with the amount of space you want in 661da177e4SLinus Torvalds the buffer. skb_put() returns a pointer to the top (#0) of 671da177e4SLinus Torvalds that buffer. skb->len is set to the amount of space you have 681da177e4SLinus Torvalds "allocated" with skb_put(). You can then write up to skb->len 691da177e4SLinus Torvalds bytes to that buffer. If you need more, you can call skb_put() 701da177e4SLinus Torvalds again with the additional amount of space you need. You can 711da177e4SLinus Torvalds find out how much more space you can allocate by calling 721da177e4SLinus Torvalds "skb_tailroom(skb)". 731da177e4SLinus Torvalds Now, to add header space, call "skb_push(skb, header_len)". 741da177e4SLinus Torvalds This creates space at the beginning of the buffer and returns 751da177e4SLinus Torvalds a pointer to this new space. If later you need to strip a 761da177e4SLinus Torvalds header from a buffer, call "skb_pull(skb, header_len)". 771da177e4SLinus Torvalds skb_headroom() will return how much space is left at the top 781da177e4SLinus Torvalds of the buffer (before the main data). Remember, this headroom 791da177e4SLinus Torvalds space must be reserved before the skb_put() function is called. 801da177e4SLinus Torvalds */ 811da177e4SLinus Torvalds 821da177e4SLinus Torvalds /* 831da177e4SLinus Torvalds This version of net/ipv4/ipip.c is cloned of net/ipv4/ip_gre.c 841da177e4SLinus Torvalds 851da177e4SLinus Torvalds For comments look at net/ipv4/ip_gre.c --ANK 861da177e4SLinus Torvalds */ 871da177e4SLinus Torvalds 881da177e4SLinus Torvalds 894fc268d2SRandy Dunlap #include <linux/capability.h> 901da177e4SLinus Torvalds #include <linux/module.h> 911da177e4SLinus Torvalds #include <linux/types.h> 921da177e4SLinus Torvalds #include <linux/kernel.h> 935a0e3ad6STejun Heo #include <linux/slab.h> 947c0f6ba6SLinus Torvalds #include <linux/uaccess.h> 951da177e4SLinus Torvalds #include <linux/skbuff.h> 961da177e4SLinus Torvalds #include <linux/netdevice.h> 971da177e4SLinus Torvalds #include <linux/in.h> 981da177e4SLinus Torvalds #include <linux/tcp.h> 991da177e4SLinus Torvalds #include <linux/udp.h> 1001da177e4SLinus Torvalds #include <linux/if_arp.h> 1011da177e4SLinus Torvalds #include <linux/init.h> 1021da177e4SLinus Torvalds #include <linux/netfilter_ipv4.h> 10346f25dffSKris Katterjohn #include <linux/if_ether.h> 1041da177e4SLinus Torvalds 1051da177e4SLinus Torvalds #include <net/sock.h> 1061da177e4SLinus Torvalds #include <net/ip.h> 1071da177e4SLinus Torvalds #include <net/icmp.h> 108c5441932SPravin B Shelar #include <net/ip_tunnels.h> 1091da177e4SLinus Torvalds #include <net/inet_ecn.h> 1101da177e4SLinus Torvalds #include <net/xfrm.h> 11110dc4c7bSPavel Emelyanov #include <net/net_namespace.h> 11210dc4c7bSPavel Emelyanov #include <net/netns/generic.h> 113cfc7381bSAlexei Starovoitov #include <net/dst_metadata.h> 1141da177e4SLinus Torvalds 115eccc1bb8Sstephen hemminger static bool log_ecn_error = true; 116eccc1bb8Sstephen hemminger module_param(log_ecn_error, bool, 0644); 117eccc1bb8Sstephen hemminger MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN"); 118eccc1bb8Sstephen hemminger 119c7d03a00SAlexey Dobriyan static unsigned int ipip_net_id __read_mostly; 12010dc4c7bSPavel Emelyanov 1213c97af99SEric Dumazet static int ipip_tunnel_init(struct net_device *dev); 1220974658dSNicolas Dichtel static struct rtnl_link_ops ipip_link_ops __read_mostly; 1231da177e4SLinus Torvalds 124d2acc347SHerbert Xu static int ipip_err(struct sk_buff *skb, u32 info) 1251da177e4SLinus Torvalds { 126071f92d0SRami Rosen /* All the routers (except for Linux) return only 127f3594f0aSXin Long * 8 bytes of packet payload. It means, that precise relaying of 128f3594f0aSXin Long * ICMP in the real Internet is absolutely infeasible. 1291da177e4SLinus Torvalds */ 130fd58156eSPravin B Shelar struct net *net = dev_net(skb->dev); 131fd58156eSPravin B Shelar struct ip_tunnel_net *itn = net_generic(net, ipip_net_id); 132b71d1d42SEric Dumazet const struct iphdr *iph = (const struct iphdr *)skb->data; 1335832c4a7SAlexander Lobakin IP_TUNNEL_DECLARE_FLAGS(flags) = { }; 134fd58156eSPravin B Shelar const int type = icmp_hdr(skb)->type; 135fd58156eSPravin B Shelar const int code = icmp_hdr(skb)->code; 136f3594f0aSXin Long struct ip_tunnel *t; 137f3594f0aSXin Long int err = 0; 1381da177e4SLinus Torvalds 1395832c4a7SAlexander Lobakin __set_bit(IP_TUNNEL_NO_KEY_BIT, flags); 1405832c4a7SAlexander Lobakin 1415832c4a7SAlexander Lobakin t = ip_tunnel_lookup(itn, skb->dev->ifindex, flags, iph->daddr, 1425832c4a7SAlexander Lobakin iph->saddr, 0); 14332bbd879SStefano Brivio if (!t) { 14432bbd879SStefano Brivio err = -ENOENT; 14532bbd879SStefano Brivio goto out; 14632bbd879SStefano Brivio } 14732bbd879SStefano Brivio 148f3594f0aSXin Long switch (type) { 149f3594f0aSXin Long case ICMP_DEST_UNREACH: 150f3594f0aSXin Long switch (code) { 151f3594f0aSXin Long case ICMP_SR_FAILED: 152f3594f0aSXin Long /* Impossible event. */ 153f3594f0aSXin Long goto out; 154f3594f0aSXin Long default: 155f3594f0aSXin Long /* All others are translated to HOST_UNREACH. 156f3594f0aSXin Long * rfc2003 contains "deep thoughts" about NET_UNREACH, 157f3594f0aSXin Long * I believe they are just ether pollution. --ANK 158f3594f0aSXin Long */ 159f3594f0aSXin Long break; 160f3594f0aSXin Long } 161f3594f0aSXin Long break; 162f3594f0aSXin Long 163f3594f0aSXin Long case ICMP_TIME_EXCEEDED: 164f3594f0aSXin Long if (code != ICMP_EXC_TTL) 165f3594f0aSXin Long goto out; 166f3594f0aSXin Long break; 167f3594f0aSXin Long 168f3594f0aSXin Long case ICMP_REDIRECT: 169f3594f0aSXin Long break; 170f3594f0aSXin Long 171f3594f0aSXin Long default: 172f3594f0aSXin Long goto out; 173f3594f0aSXin Long } 174f3594f0aSXin Long 17536393395SDavid S. Miller if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) { 176d888f396SMaciej Żenczykowski ipv4_update_pmtu(skb, net, info, t->parms.link, iph->protocol); 17736393395SDavid S. Miller goto out; 17836393395SDavid S. Miller } 17936393395SDavid S. Miller 18055be7a9cSDavid S. Miller if (type == ICMP_REDIRECT) { 1811042caa7SMaciej Żenczykowski ipv4_redirect(skb, net, t->parms.link, iph->protocol); 18255be7a9cSDavid S. Miller goto out; 18355be7a9cSDavid S. Miller } 18455be7a9cSDavid S. Miller 185f3594f0aSXin Long if (t->parms.iph.daddr == 0) { 186f3594f0aSXin Long err = -ENOENT; 1871da177e4SLinus Torvalds goto out; 188f3594f0aSXin Long } 189d2acc347SHerbert Xu 1901da177e4SLinus Torvalds if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED) 1911da177e4SLinus Torvalds goto out; 1921da177e4SLinus Torvalds 19326d94b46SWei Yongjun if (time_before(jiffies, t->err_time + IPTUNNEL_ERR_TIMEO)) 1941da177e4SLinus Torvalds t->err_count++; 1951da177e4SLinus Torvalds else 1961da177e4SLinus Torvalds t->err_count = 1; 1971da177e4SLinus Torvalds t->err_time = jiffies; 198b0558ef2Sstephen hemminger 199fd58156eSPravin B Shelar out: 200d2acc347SHerbert Xu return err; 2011da177e4SLinus Torvalds } 2021da177e4SLinus Torvalds 2031b69e7e6SSimon Horman static const struct tnl_ptk_info ipip_tpi = { 204fd58156eSPravin B Shelar /* no tunnel info required for ipip. */ 205fd58156eSPravin B Shelar .proto = htons(ETH_P_IP), 206fd58156eSPravin B Shelar }; 207fd58156eSPravin B Shelar 2081b69e7e6SSimon Horman #if IS_ENABLED(CONFIG_MPLS) 2091b69e7e6SSimon Horman static const struct tnl_ptk_info mplsip_tpi = { 2101b69e7e6SSimon Horman /* no tunnel info required for mplsip. */ 2111b69e7e6SSimon Horman .proto = htons(ETH_P_MPLS_UC), 2121b69e7e6SSimon Horman }; 2131b69e7e6SSimon Horman #endif 2141b69e7e6SSimon Horman 2151b69e7e6SSimon Horman static int ipip_tunnel_rcv(struct sk_buff *skb, u8 ipproto) 2161da177e4SLinus Torvalds { 217fd58156eSPravin B Shelar struct net *net = dev_net(skb->dev); 218fd58156eSPravin B Shelar struct ip_tunnel_net *itn = net_generic(net, ipip_net_id); 2195832c4a7SAlexander Lobakin IP_TUNNEL_DECLARE_FLAGS(flags) = { }; 220cfc7381bSAlexei Starovoitov struct metadata_dst *tun_dst = NULL; 2211da177e4SLinus Torvalds struct ip_tunnel *tunnel; 2223d7b46cdSPravin B Shelar const struct iphdr *iph; 2231da177e4SLinus Torvalds 2245832c4a7SAlexander Lobakin __set_bit(IP_TUNNEL_NO_KEY_BIT, flags); 2255832c4a7SAlexander Lobakin 2263d7b46cdSPravin B Shelar iph = ip_hdr(skb); 2275832c4a7SAlexander Lobakin tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, flags, iph->saddr, 2285832c4a7SAlexander Lobakin iph->daddr, 0); 229fd58156eSPravin B Shelar if (tunnel) { 2301b69e7e6SSimon Horman const struct tnl_ptk_info *tpi; 2311b69e7e6SSimon Horman 2321b69e7e6SSimon Horman if (tunnel->parms.iph.protocol != ipproto && 2331b69e7e6SSimon Horman tunnel->parms.iph.protocol != 0) 2341b69e7e6SSimon Horman goto drop; 2351b69e7e6SSimon Horman 236eccc1bb8Sstephen hemminger if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) 237eccc1bb8Sstephen hemminger goto drop; 2381b69e7e6SSimon Horman #if IS_ENABLED(CONFIG_MPLS) 2391b69e7e6SSimon Horman if (ipproto == IPPROTO_MPLS) 2401b69e7e6SSimon Horman tpi = &mplsip_tpi; 2411b69e7e6SSimon Horman else 2421b69e7e6SSimon Horman #endif 2431b69e7e6SSimon Horman tpi = &ipip_tpi; 2441b69e7e6SSimon Horman if (iptunnel_pull_header(skb, 0, tpi->proto, false)) 245737e828bSLi Hongjun goto drop; 246cfc7381bSAlexei Starovoitov if (tunnel->collect_md) { 2475832c4a7SAlexander Lobakin ip_tunnel_flags_zero(flags); 2485832c4a7SAlexander Lobakin 2495832c4a7SAlexander Lobakin tun_dst = ip_tun_rx_dst(skb, flags, 0, 0); 250cfc7381bSAlexei Starovoitov if (!tun_dst) 251cfc7381bSAlexei Starovoitov return 0; 252ac931d4cSChristian Ehrig ip_tunnel_md_udp_encap(skb, &tun_dst->u.tun_info); 253cfc7381bSAlexei Starovoitov } 2547ad136fdSGuillaume Nault skb_reset_mac_header(skb); 2557ad136fdSGuillaume Nault 256cfc7381bSAlexei Starovoitov return ip_tunnel_rcv(tunnel, skb, tpi, tun_dst, log_ecn_error); 2571da177e4SLinus Torvalds } 2581da177e4SLinus Torvalds 2591da177e4SLinus Torvalds return -1; 260eccc1bb8Sstephen hemminger 261eccc1bb8Sstephen hemminger drop: 262eccc1bb8Sstephen hemminger kfree_skb(skb); 263eccc1bb8Sstephen hemminger return 0; 2641da177e4SLinus Torvalds } 2651da177e4SLinus Torvalds 2661b69e7e6SSimon Horman static int ipip_rcv(struct sk_buff *skb) 2671b69e7e6SSimon Horman { 2681b69e7e6SSimon Horman return ipip_tunnel_rcv(skb, IPPROTO_IPIP); 2691b69e7e6SSimon Horman } 2701b69e7e6SSimon Horman 2711b69e7e6SSimon Horman #if IS_ENABLED(CONFIG_MPLS) 2721b69e7e6SSimon Horman static int mplsip_rcv(struct sk_buff *skb) 2731b69e7e6SSimon Horman { 2741b69e7e6SSimon Horman return ipip_tunnel_rcv(skb, IPPROTO_MPLS); 2751b69e7e6SSimon Horman } 2761b69e7e6SSimon Horman #endif 2771b69e7e6SSimon Horman 2781da177e4SLinus Torvalds /* 2791da177e4SLinus Torvalds * This function assumes it is being called from dev_queue_xmit() 2801da177e4SLinus Torvalds * and that skb is filled properly by that function. 2811da177e4SLinus Torvalds */ 2821b69e7e6SSimon Horman static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, 2831b69e7e6SSimon Horman struct net_device *dev) 2841da177e4SLinus Torvalds { 2852941a486SPatrick McHardy struct ip_tunnel *tunnel = netdev_priv(dev); 286b71d1d42SEric Dumazet const struct iphdr *tiph = &tunnel->parms.iph; 2871b69e7e6SSimon Horman u8 ipproto; 2881da177e4SLinus Torvalds 28947d858d0SHaishuang Yan if (!pskb_inet_may_pull(skb)) 29047d858d0SHaishuang Yan goto tx_error; 29147d858d0SHaishuang Yan 2921b69e7e6SSimon Horman switch (skb->protocol) { 2931b69e7e6SSimon Horman case htons(ETH_P_IP): 2941b69e7e6SSimon Horman ipproto = IPPROTO_IPIP; 2951b69e7e6SSimon Horman break; 2961b69e7e6SSimon Horman #if IS_ENABLED(CONFIG_MPLS) 2971b69e7e6SSimon Horman case htons(ETH_P_MPLS_UC): 2981b69e7e6SSimon Horman ipproto = IPPROTO_MPLS; 2991b69e7e6SSimon Horman break; 3001b69e7e6SSimon Horman #endif 3011b69e7e6SSimon Horman default: 3021b69e7e6SSimon Horman goto tx_error; 3031b69e7e6SSimon Horman } 3041b69e7e6SSimon Horman 3051b69e7e6SSimon Horman if (tiph->protocol != ipproto && tiph->protocol != 0) 3061da177e4SLinus Torvalds goto tx_error; 307cef401deSEric Dumazet 3087e13318dSTom Herbert if (iptunnel_handle_offloads(skb, SKB_GSO_IPXIP4)) 309aed069dfSAlexander Duyck goto tx_error; 3104f3ed920SPravin B Shelar 3111b69e7e6SSimon Horman skb_set_inner_ipproto(skb, ipproto); 312077c5a09STom Herbert 313cfc7381bSAlexei Starovoitov if (tunnel->collect_md) 314c8b34e68Swenxu ip_md_tunnel_xmit(skb, dev, ipproto, 0); 315cfc7381bSAlexei Starovoitov else 3161b69e7e6SSimon Horman ip_tunnel_xmit(skb, dev, tiph, ipproto); 3176ed10654SPatrick McHardy return NETDEV_TX_OK; 3181da177e4SLinus Torvalds 3191da177e4SLinus Torvalds tx_error: 3203acfa1e7SEric Dumazet kfree_skb(skb); 321aed069dfSAlexander Duyck 322c4794d22SEric Dumazet DEV_STATS_INC(dev, tx_errors); 3236ed10654SPatrick McHardy return NETDEV_TX_OK; 3241da177e4SLinus Torvalds } 3251da177e4SLinus Torvalds 3261b69e7e6SSimon Horman static bool ipip_tunnel_ioctl_verify_protocol(u8 ipproto) 3271b69e7e6SSimon Horman { 3281b69e7e6SSimon Horman switch (ipproto) { 3291b69e7e6SSimon Horman case 0: 3301b69e7e6SSimon Horman case IPPROTO_IPIP: 3311b69e7e6SSimon Horman #if IS_ENABLED(CONFIG_MPLS) 3321b69e7e6SSimon Horman case IPPROTO_MPLS: 3331b69e7e6SSimon Horman #endif 3341b69e7e6SSimon Horman return true; 3351b69e7e6SSimon Horman } 3361b69e7e6SSimon Horman 3371b69e7e6SSimon Horman return false; 3381b69e7e6SSimon Horman } 3391b69e7e6SSimon Horman 3401da177e4SLinus Torvalds static int 341117aef12SAlexander Lobakin ipip_tunnel_ctl(struct net_device *dev, struct ip_tunnel_parm_kern *p, int cmd) 3421da177e4SLinus Torvalds { 3433b7b514fSCong Wang if (cmd == SIOCADDTUNNEL || cmd == SIOCCHGTUNNEL) { 344607259a6SChristoph Hellwig if (p->iph.version != 4 || 345607259a6SChristoph Hellwig !ipip_tunnel_ioctl_verify_protocol(p->iph.protocol) || 346607259a6SChristoph Hellwig p->iph.ihl != 5 || (p->iph.frag_off & htons(~IP_DF))) 347fd58156eSPravin B Shelar return -EINVAL; 3483b7b514fSCong Wang } 3493b7b514fSCong Wang 350607259a6SChristoph Hellwig p->i_key = p->o_key = 0; 3515832c4a7SAlexander Lobakin ip_tunnel_flags_zero(p->i_flags); 3525832c4a7SAlexander Lobakin ip_tunnel_flags_zero(p->o_flags); 353607259a6SChristoph Hellwig return ip_tunnel_ctl(dev, p, cmd); 3541da177e4SLinus Torvalds } 3551da177e4SLinus Torvalds 35623a12b14SStephen Hemminger static const struct net_device_ops ipip_netdev_ops = { 357fd58156eSPravin B Shelar .ndo_init = ipip_tunnel_init, 358fd58156eSPravin B Shelar .ndo_uninit = ip_tunnel_uninit, 35923a12b14SStephen Hemminger .ndo_start_xmit = ipip_tunnel_xmit, 3603e7a1c7cSArnd Bergmann .ndo_siocdevprivate = ip_tunnel_siocdevprivate, 361fd58156eSPravin B Shelar .ndo_change_mtu = ip_tunnel_change_mtu, 36298d7fc46SHeiner Kallweit .ndo_get_stats64 = dev_get_tstats64, 3631e99584bSNicolas Dichtel .ndo_get_iflink = ip_tunnel_get_iflink, 364607259a6SChristoph Hellwig .ndo_tunnel_ctl = ipip_tunnel_ctl, 36523a12b14SStephen Hemminger }; 36623a12b14SStephen Hemminger 367c3b89fbbSEric Dumazet #define IPIP_FEATURES (NETIF_F_SG | \ 368c3b89fbbSEric Dumazet NETIF_F_FRAGLIST | \ 369c3b89fbbSEric Dumazet NETIF_F_HIGHDMA | \ 370cb32f511SEric Dumazet NETIF_F_GSO_SOFTWARE | \ 371c3b89fbbSEric Dumazet NETIF_F_HW_CSUM) 372c3b89fbbSEric Dumazet 3731da177e4SLinus Torvalds static void ipip_tunnel_setup(struct net_device *dev) 3741da177e4SLinus Torvalds { 37523a12b14SStephen Hemminger dev->netdev_ops = &ipip_netdev_ops; 376e53ac932SJason A. Donenfeld dev->header_ops = &ip_tunnel_header_ops; 3771da177e4SLinus Torvalds 3781da177e4SLinus Torvalds dev->type = ARPHRD_TUNNEL; 3791da177e4SLinus Torvalds dev->flags = IFF_NOARP; 3801da177e4SLinus Torvalds dev->addr_len = 4; 381*00d066a4SAlexander Lobakin dev->lltx = true; 38202875878SEric Dumazet netif_keep_dst(dev); 383c3b89fbbSEric Dumazet 384c3b89fbbSEric Dumazet dev->features |= IPIP_FEATURES; 385c3b89fbbSEric Dumazet dev->hw_features |= IPIP_FEATURES; 386fd58156eSPravin B Shelar ip_tunnel_setup(dev, ipip_net_id); 3871da177e4SLinus Torvalds } 3881da177e4SLinus Torvalds 3893c97af99SEric Dumazet static int ipip_tunnel_init(struct net_device *dev) 3901da177e4SLinus Torvalds { 39123a12b14SStephen Hemminger struct ip_tunnel *tunnel = netdev_priv(dev); 3921da177e4SLinus Torvalds 3935a1b7e1aSJakub Kicinski __dev_addr_set(dev, &tunnel->parms.iph.saddr, 4); 3941da177e4SLinus Torvalds memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4); 3951da177e4SLinus Torvalds 396473ab820STom Herbert tunnel->tun_hlen = 0; 397473ab820STom Herbert tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen; 398fd58156eSPravin B Shelar return ip_tunnel_init(dev); 3991da177e4SLinus Torvalds } 4001da177e4SLinus Torvalds 401a8b8a889SMatthias Schiffer static int ipip_tunnel_validate(struct nlattr *tb[], struct nlattr *data[], 402a8b8a889SMatthias Schiffer struct netlink_ext_ack *extack) 4031b69e7e6SSimon Horman { 4041b69e7e6SSimon Horman u8 proto; 4051b69e7e6SSimon Horman 4061b69e7e6SSimon Horman if (!data || !data[IFLA_IPTUN_PROTO]) 4071b69e7e6SSimon Horman return 0; 4081b69e7e6SSimon Horman 4091b69e7e6SSimon Horman proto = nla_get_u8(data[IFLA_IPTUN_PROTO]); 4101b69e7e6SSimon Horman if (proto != IPPROTO_IPIP && proto != IPPROTO_MPLS && proto != 0) 4111b69e7e6SSimon Horman return -EINVAL; 4121b69e7e6SSimon Horman 4131b69e7e6SSimon Horman return 0; 4141b69e7e6SSimon Horman } 4151b69e7e6SSimon Horman 416be42da0eSNicolas Dichtel static void ipip_netlink_parms(struct nlattr *data[], 417117aef12SAlexander Lobakin struct ip_tunnel_parm_kern *parms, 418117aef12SAlexander Lobakin bool *collect_md, __u32 *fwmark) 419be42da0eSNicolas Dichtel { 420be42da0eSNicolas Dichtel memset(parms, 0, sizeof(*parms)); 421be42da0eSNicolas Dichtel 422be42da0eSNicolas Dichtel parms->iph.version = 4; 423be42da0eSNicolas Dichtel parms->iph.protocol = IPPROTO_IPIP; 424be42da0eSNicolas Dichtel parms->iph.ihl = 5; 425cfc7381bSAlexei Starovoitov *collect_md = false; 426be42da0eSNicolas Dichtel 427be42da0eSNicolas Dichtel if (!data) 428be42da0eSNicolas Dichtel return; 429be42da0eSNicolas Dichtel 430b86fca80SLiu Jian ip_tunnel_netlink_parms(data, parms); 431cfc7381bSAlexei Starovoitov 432cfc7381bSAlexei Starovoitov if (data[IFLA_IPTUN_COLLECT_METADATA]) 433cfc7381bSAlexei Starovoitov *collect_md = true; 4349830ad4cSCraig Gallek 4359830ad4cSCraig Gallek if (data[IFLA_IPTUN_FWMARK]) 4369830ad4cSCraig Gallek *fwmark = nla_get_u32(data[IFLA_IPTUN_FWMARK]); 437be42da0eSNicolas Dichtel } 438be42da0eSNicolas Dichtel 439be42da0eSNicolas Dichtel static int ipip_newlink(struct net *src_net, struct net_device *dev, 4407a3f4a18SMatthias Schiffer struct nlattr *tb[], struct nlattr *data[], 4417a3f4a18SMatthias Schiffer struct netlink_ext_ack *extack) 442be42da0eSNicolas Dichtel { 443cfc7381bSAlexei Starovoitov struct ip_tunnel *t = netdev_priv(dev); 444473ab820STom Herbert struct ip_tunnel_encap ipencap; 445117aef12SAlexander Lobakin struct ip_tunnel_parm_kern p; 4469830ad4cSCraig Gallek __u32 fwmark = 0; 447473ab820STom Herbert 448537dd2d9SLiu Jian if (ip_tunnel_netlink_encap_parms(data, &ipencap)) { 449473ab820STom Herbert int err = ip_tunnel_encap_setup(t, &ipencap); 450473ab820STom Herbert 451473ab820STom Herbert if (err < 0) 452473ab820STom Herbert return err; 453473ab820STom Herbert } 454be42da0eSNicolas Dichtel 4559830ad4cSCraig Gallek ipip_netlink_parms(data, &p, &t->collect_md, &fwmark); 4569830ad4cSCraig Gallek return ip_tunnel_newlink(dev, tb, &p, fwmark); 457be42da0eSNicolas Dichtel } 458be42da0eSNicolas Dichtel 459be42da0eSNicolas Dichtel static int ipip_changelink(struct net_device *dev, struct nlattr *tb[], 460ad744b22SMatthias Schiffer struct nlattr *data[], 461ad744b22SMatthias Schiffer struct netlink_ext_ack *extack) 462be42da0eSNicolas Dichtel { 4639830ad4cSCraig Gallek struct ip_tunnel *t = netdev_priv(dev); 464473ab820STom Herbert struct ip_tunnel_encap ipencap; 465117aef12SAlexander Lobakin struct ip_tunnel_parm_kern p; 466cfc7381bSAlexei Starovoitov bool collect_md; 4679830ad4cSCraig Gallek __u32 fwmark = t->fwmark; 468473ab820STom Herbert 469537dd2d9SLiu Jian if (ip_tunnel_netlink_encap_parms(data, &ipencap)) { 470473ab820STom Herbert int err = ip_tunnel_encap_setup(t, &ipencap); 471473ab820STom Herbert 472473ab820STom Herbert if (err < 0) 473473ab820STom Herbert return err; 474473ab820STom Herbert } 475be42da0eSNicolas Dichtel 4769830ad4cSCraig Gallek ipip_netlink_parms(data, &p, &collect_md, &fwmark); 477cfc7381bSAlexei Starovoitov if (collect_md) 478cfc7381bSAlexei Starovoitov return -EINVAL; 479be42da0eSNicolas Dichtel 480be42da0eSNicolas Dichtel if (((dev->flags & IFF_POINTOPOINT) && !p.iph.daddr) || 481be42da0eSNicolas Dichtel (!(dev->flags & IFF_POINTOPOINT) && p.iph.daddr)) 482be42da0eSNicolas Dichtel return -EINVAL; 483be42da0eSNicolas Dichtel 4849830ad4cSCraig Gallek return ip_tunnel_changelink(dev, tb, &p, fwmark); 485be42da0eSNicolas Dichtel } 486be42da0eSNicolas Dichtel 4870974658dSNicolas Dichtel static size_t ipip_get_size(const struct net_device *dev) 4880974658dSNicolas Dichtel { 4890974658dSNicolas Dichtel return 4900974658dSNicolas Dichtel /* IFLA_IPTUN_LINK */ 4910974658dSNicolas Dichtel nla_total_size(4) + 4920974658dSNicolas Dichtel /* IFLA_IPTUN_LOCAL */ 4930974658dSNicolas Dichtel nla_total_size(4) + 4940974658dSNicolas Dichtel /* IFLA_IPTUN_REMOTE */ 4950974658dSNicolas Dichtel nla_total_size(4) + 4960974658dSNicolas Dichtel /* IFLA_IPTUN_TTL */ 4970974658dSNicolas Dichtel nla_total_size(1) + 4980974658dSNicolas Dichtel /* IFLA_IPTUN_TOS */ 4990974658dSNicolas Dichtel nla_total_size(1) + 5001b69e7e6SSimon Horman /* IFLA_IPTUN_PROTO */ 5011b69e7e6SSimon Horman nla_total_size(1) + 502befe2aa1SNicolas Dichtel /* IFLA_IPTUN_PMTUDISC */ 503befe2aa1SNicolas Dichtel nla_total_size(1) + 504473ab820STom Herbert /* IFLA_IPTUN_ENCAP_TYPE */ 505473ab820STom Herbert nla_total_size(2) + 506473ab820STom Herbert /* IFLA_IPTUN_ENCAP_FLAGS */ 507473ab820STom Herbert nla_total_size(2) + 508473ab820STom Herbert /* IFLA_IPTUN_ENCAP_SPORT */ 509473ab820STom Herbert nla_total_size(2) + 510473ab820STom Herbert /* IFLA_IPTUN_ENCAP_DPORT */ 511473ab820STom Herbert nla_total_size(2) + 512cfc7381bSAlexei Starovoitov /* IFLA_IPTUN_COLLECT_METADATA */ 513cfc7381bSAlexei Starovoitov nla_total_size(0) + 5149830ad4cSCraig Gallek /* IFLA_IPTUN_FWMARK */ 5159830ad4cSCraig Gallek nla_total_size(4) + 5160974658dSNicolas Dichtel 0; 5170974658dSNicolas Dichtel } 5180974658dSNicolas Dichtel 5190974658dSNicolas Dichtel static int ipip_fill_info(struct sk_buff *skb, const struct net_device *dev) 5200974658dSNicolas Dichtel { 5210974658dSNicolas Dichtel struct ip_tunnel *tunnel = netdev_priv(dev); 522117aef12SAlexander Lobakin struct ip_tunnel_parm_kern *parm = &tunnel->parms; 5230974658dSNicolas Dichtel 5240974658dSNicolas Dichtel if (nla_put_u32(skb, IFLA_IPTUN_LINK, parm->link) || 525930345eaSJiri Benc nla_put_in_addr(skb, IFLA_IPTUN_LOCAL, parm->iph.saddr) || 526930345eaSJiri Benc nla_put_in_addr(skb, IFLA_IPTUN_REMOTE, parm->iph.daddr) || 5270974658dSNicolas Dichtel nla_put_u8(skb, IFLA_IPTUN_TTL, parm->iph.ttl) || 528befe2aa1SNicolas Dichtel nla_put_u8(skb, IFLA_IPTUN_TOS, parm->iph.tos) || 5291b69e7e6SSimon Horman nla_put_u8(skb, IFLA_IPTUN_PROTO, parm->iph.protocol) || 530befe2aa1SNicolas Dichtel nla_put_u8(skb, IFLA_IPTUN_PMTUDISC, 5319830ad4cSCraig Gallek !!(parm->iph.frag_off & htons(IP_DF))) || 5329830ad4cSCraig Gallek nla_put_u32(skb, IFLA_IPTUN_FWMARK, tunnel->fwmark)) 5330974658dSNicolas Dichtel goto nla_put_failure; 534473ab820STom Herbert 535473ab820STom Herbert if (nla_put_u16(skb, IFLA_IPTUN_ENCAP_TYPE, 536473ab820STom Herbert tunnel->encap.type) || 5373e97fa70SSabrina Dubroca nla_put_be16(skb, IFLA_IPTUN_ENCAP_SPORT, 538473ab820STom Herbert tunnel->encap.sport) || 5393e97fa70SSabrina Dubroca nla_put_be16(skb, IFLA_IPTUN_ENCAP_DPORT, 540473ab820STom Herbert tunnel->encap.dport) || 541473ab820STom Herbert nla_put_u16(skb, IFLA_IPTUN_ENCAP_FLAGS, 542e1b2cb65STom Herbert tunnel->encap.flags)) 543473ab820STom Herbert goto nla_put_failure; 544473ab820STom Herbert 545cfc7381bSAlexei Starovoitov if (tunnel->collect_md) 546cfc7381bSAlexei Starovoitov if (nla_put_flag(skb, IFLA_IPTUN_COLLECT_METADATA)) 547cfc7381bSAlexei Starovoitov goto nla_put_failure; 5480974658dSNicolas Dichtel return 0; 5490974658dSNicolas Dichtel 5500974658dSNicolas Dichtel nla_put_failure: 5510974658dSNicolas Dichtel return -EMSGSIZE; 5520974658dSNicolas Dichtel } 5530974658dSNicolas Dichtel 554be42da0eSNicolas Dichtel static const struct nla_policy ipip_policy[IFLA_IPTUN_MAX + 1] = { 555be42da0eSNicolas Dichtel [IFLA_IPTUN_LINK] = { .type = NLA_U32 }, 556be42da0eSNicolas Dichtel [IFLA_IPTUN_LOCAL] = { .type = NLA_U32 }, 557be42da0eSNicolas Dichtel [IFLA_IPTUN_REMOTE] = { .type = NLA_U32 }, 558be42da0eSNicolas Dichtel [IFLA_IPTUN_TTL] = { .type = NLA_U8 }, 559be42da0eSNicolas Dichtel [IFLA_IPTUN_TOS] = { .type = NLA_U8 }, 5601b69e7e6SSimon Horman [IFLA_IPTUN_PROTO] = { .type = NLA_U8 }, 561be42da0eSNicolas Dichtel [IFLA_IPTUN_PMTUDISC] = { .type = NLA_U8 }, 562473ab820STom Herbert [IFLA_IPTUN_ENCAP_TYPE] = { .type = NLA_U16 }, 563473ab820STom Herbert [IFLA_IPTUN_ENCAP_FLAGS] = { .type = NLA_U16 }, 564473ab820STom Herbert [IFLA_IPTUN_ENCAP_SPORT] = { .type = NLA_U16 }, 565473ab820STom Herbert [IFLA_IPTUN_ENCAP_DPORT] = { .type = NLA_U16 }, 566cfc7381bSAlexei Starovoitov [IFLA_IPTUN_COLLECT_METADATA] = { .type = NLA_FLAG }, 5679830ad4cSCraig Gallek [IFLA_IPTUN_FWMARK] = { .type = NLA_U32 }, 568be42da0eSNicolas Dichtel }; 569be42da0eSNicolas Dichtel 5700974658dSNicolas Dichtel static struct rtnl_link_ops ipip_link_ops __read_mostly = { 5710974658dSNicolas Dichtel .kind = "ipip", 5720974658dSNicolas Dichtel .maxtype = IFLA_IPTUN_MAX, 573be42da0eSNicolas Dichtel .policy = ipip_policy, 5740974658dSNicolas Dichtel .priv_size = sizeof(struct ip_tunnel), 575be42da0eSNicolas Dichtel .setup = ipip_tunnel_setup, 5761b69e7e6SSimon Horman .validate = ipip_tunnel_validate, 577be42da0eSNicolas Dichtel .newlink = ipip_newlink, 578be42da0eSNicolas Dichtel .changelink = ipip_changelink, 579fd58156eSPravin B Shelar .dellink = ip_tunnel_dellink, 5800974658dSNicolas Dichtel .get_size = ipip_get_size, 5810974658dSNicolas Dichtel .fill_info = ipip_fill_info, 5821728d4faSNicolas Dichtel .get_link_net = ip_tunnel_get_link_net, 5830974658dSNicolas Dichtel }; 5840974658dSNicolas Dichtel 5856dcd814bSEric Dumazet static struct xfrm_tunnel ipip_handler __read_mostly = { 5861da177e4SLinus Torvalds .handler = ipip_rcv, 5871da177e4SLinus Torvalds .err_handler = ipip_err, 588d2acc347SHerbert Xu .priority = 1, 5891da177e4SLinus Torvalds }; 5901da177e4SLinus Torvalds 5911b69e7e6SSimon Horman #if IS_ENABLED(CONFIG_MPLS) 5921b69e7e6SSimon Horman static struct xfrm_tunnel mplsip_handler __read_mostly = { 5931b69e7e6SSimon Horman .handler = mplsip_rcv, 5941b69e7e6SSimon Horman .err_handler = ipip_err, 5951b69e7e6SSimon Horman .priority = 1, 5961b69e7e6SSimon Horman }; 5971b69e7e6SSimon Horman #endif 5981b69e7e6SSimon Horman 5992c8c1e72SAlexey Dobriyan static int __net_init ipip_init_net(struct net *net) 60010dc4c7bSPavel Emelyanov { 601fd58156eSPravin B Shelar return ip_tunnel_init_net(net, ipip_net_id, &ipip_link_ops, "tunl0"); 60210dc4c7bSPavel Emelyanov } 60310dc4c7bSPavel Emelyanov 6049b5b3637SEric Dumazet static void __net_exit ipip_exit_batch_rtnl(struct list_head *list_net, 6059b5b3637SEric Dumazet struct list_head *dev_to_kill) 60610dc4c7bSPavel Emelyanov { 6079b5b3637SEric Dumazet ip_tunnel_delete_nets(list_net, ipip_net_id, &ipip_link_ops, 6089b5b3637SEric Dumazet dev_to_kill); 60910dc4c7bSPavel Emelyanov } 61010dc4c7bSPavel Emelyanov 61110dc4c7bSPavel Emelyanov static struct pernet_operations ipip_net_ops = { 61210dc4c7bSPavel Emelyanov .init = ipip_init_net, 6139b5b3637SEric Dumazet .exit_batch_rtnl = ipip_exit_batch_rtnl, 61486de8a63SEric W. Biederman .id = &ipip_net_id, 615fd58156eSPravin B Shelar .size = sizeof(struct ip_tunnel_net), 61610dc4c7bSPavel Emelyanov }; 61710dc4c7bSPavel Emelyanov 6181da177e4SLinus Torvalds static int __init ipip_init(void) 6191da177e4SLinus Torvalds { 6201da177e4SLinus Torvalds int err; 6211da177e4SLinus Torvalds 6221b69e7e6SSimon Horman pr_info("ipip: IPv4 and MPLS over IPv4 tunneling driver\n"); 6231da177e4SLinus Torvalds 62486de8a63SEric W. Biederman err = register_pernet_device(&ipip_net_ops); 625d5aa407fSAlexey Dobriyan if (err < 0) 626d5aa407fSAlexey Dobriyan return err; 627d5aa407fSAlexey Dobriyan err = xfrm4_tunnel_register(&ipip_handler, AF_INET); 628d5aa407fSAlexey Dobriyan if (err < 0) { 629058bd4d2SJoe Perches pr_info("%s: can't register tunnel\n", __func__); 6301b69e7e6SSimon Horman goto xfrm_tunnel_ipip_failed; 631d5aa407fSAlexey Dobriyan } 6321b69e7e6SSimon Horman #if IS_ENABLED(CONFIG_MPLS) 6331b69e7e6SSimon Horman err = xfrm4_tunnel_register(&mplsip_handler, AF_MPLS); 6341b69e7e6SSimon Horman if (err < 0) { 6351b69e7e6SSimon Horman pr_info("%s: can't register tunnel\n", __func__); 6361b69e7e6SSimon Horman goto xfrm_tunnel_mplsip_failed; 6371b69e7e6SSimon Horman } 6381b69e7e6SSimon Horman #endif 6390974658dSNicolas Dichtel err = rtnl_link_register(&ipip_link_ops); 6400974658dSNicolas Dichtel if (err < 0) 6410974658dSNicolas Dichtel goto rtnl_link_failed; 6420974658dSNicolas Dichtel 6430974658dSNicolas Dichtel out: 644b9855c54SPavel Emelyanov return err; 6450974658dSNicolas Dichtel 6460974658dSNicolas Dichtel rtnl_link_failed: 6471b69e7e6SSimon Horman #if IS_ENABLED(CONFIG_MPLS) 64857ebc8f0SVadim Fedorenko xfrm4_tunnel_deregister(&mplsip_handler, AF_MPLS); 6491b69e7e6SSimon Horman xfrm_tunnel_mplsip_failed: 6501b69e7e6SSimon Horman 6511b69e7e6SSimon Horman #endif 6520974658dSNicolas Dichtel xfrm4_tunnel_deregister(&ipip_handler, AF_INET); 6531b69e7e6SSimon Horman xfrm_tunnel_ipip_failed: 6540974658dSNicolas Dichtel unregister_pernet_device(&ipip_net_ops); 6550974658dSNicolas Dichtel goto out; 6561da177e4SLinus Torvalds } 6571da177e4SLinus Torvalds 6581da177e4SLinus Torvalds static void __exit ipip_fini(void) 6591da177e4SLinus Torvalds { 6600974658dSNicolas Dichtel rtnl_link_unregister(&ipip_link_ops); 661c0d56408SKazunori MIYAZAWA if (xfrm4_tunnel_deregister(&ipip_handler, AF_INET)) 662058bd4d2SJoe Perches pr_info("%s: can't deregister tunnel\n", __func__); 6631b69e7e6SSimon Horman #if IS_ENABLED(CONFIG_MPLS) 6641b69e7e6SSimon Horman if (xfrm4_tunnel_deregister(&mplsip_handler, AF_MPLS)) 6651b69e7e6SSimon Horman pr_info("%s: can't deregister tunnel\n", __func__); 6661b69e7e6SSimon Horman #endif 66786de8a63SEric W. Biederman unregister_pernet_device(&ipip_net_ops); 6681da177e4SLinus Torvalds } 6691da177e4SLinus Torvalds 6701da177e4SLinus Torvalds module_init(ipip_init); 6711da177e4SLinus Torvalds module_exit(ipip_fini); 672b058a5d2SBreno Leitao MODULE_DESCRIPTION("IP/IP protocol decoder library"); 6731da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 674f98f89a0STom Gundersen MODULE_ALIAS_RTNL_LINK("ipip"); 6758909c9adSVasiliy Kulikov MODULE_ALIAS_NETDEV("tunl0"); 676