11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Linux NET3: IP/IP protocol decoder. 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Authors: 51da177e4SLinus Torvalds * Sam Lantinga (slouken@cs.ucdavis.edu) 02/01/95 61da177e4SLinus Torvalds * 71da177e4SLinus Torvalds * Fixes: 81da177e4SLinus Torvalds * Alan Cox : Merged and made usable non modular (its so tiny its silly as 91da177e4SLinus Torvalds * a module taking up 2 pages). 101da177e4SLinus Torvalds * Alan Cox : Fixed bug with 1.3.18 and IPIP not working (now needs to set skb->h.iph) 111da177e4SLinus Torvalds * to keep ip_forward happy. 121da177e4SLinus Torvalds * Alan Cox : More fixes for 1.3.21, and firewall fix. Maybe this will work soon 8). 131da177e4SLinus Torvalds * Kai Schulte : Fixed #defines for IP_FIREWALL->FIREWALL 141da177e4SLinus Torvalds * David Woodhouse : Perform some basic ICMP handling. 151da177e4SLinus Torvalds * IPIP Routing without decapsulation. 161da177e4SLinus Torvalds * Carlos Picoto : GRE over IP support 171da177e4SLinus Torvalds * Alexey Kuznetsov: Reworked. Really, now it is truncated version of ipv4/ip_gre.c. 181da177e4SLinus Torvalds * I do not want to merge them together. 191da177e4SLinus Torvalds * 201da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or 211da177e4SLinus Torvalds * modify it under the terms of the GNU General Public License 221da177e4SLinus Torvalds * as published by the Free Software Foundation; either version 231da177e4SLinus Torvalds * 2 of the License, or (at your option) any later version. 241da177e4SLinus Torvalds * 251da177e4SLinus Torvalds */ 261da177e4SLinus Torvalds 271da177e4SLinus Torvalds /* tunnel.c: an IP tunnel driver 281da177e4SLinus Torvalds 291da177e4SLinus Torvalds The purpose of this driver is to provide an IP tunnel through 301da177e4SLinus Torvalds which you can tunnel network traffic transparently across subnets. 311da177e4SLinus Torvalds 321da177e4SLinus Torvalds This was written by looking at Nick Holloway's dummy driver 331da177e4SLinus Torvalds Thanks for the great code! 341da177e4SLinus Torvalds 351da177e4SLinus Torvalds -Sam Lantinga (slouken@cs.ucdavis.edu) 02/01/95 361da177e4SLinus Torvalds 371da177e4SLinus Torvalds Minor tweaks: 381da177e4SLinus Torvalds Cleaned up the code a little and added some pre-1.3.0 tweaks. 391da177e4SLinus Torvalds dev->hard_header/hard_header_len changed to use no headers. 401da177e4SLinus Torvalds Comments/bracketing tweaked. 411da177e4SLinus Torvalds Made the tunnels use dev->name not tunnel: when error reporting. 421da177e4SLinus Torvalds Added tx_dropped stat 431da177e4SLinus Torvalds 44113aa838SAlan Cox -Alan Cox (alan@lxorguk.ukuu.org.uk) 21 March 95 451da177e4SLinus Torvalds 461da177e4SLinus Torvalds Reworked: 471da177e4SLinus Torvalds Changed to tunnel to destination gateway in addition to the 481da177e4SLinus Torvalds tunnel's pointopoint address 491da177e4SLinus Torvalds Almost completely rewritten 501da177e4SLinus Torvalds Note: There is currently no firewall or ICMP handling done. 511da177e4SLinus Torvalds 521da177e4SLinus Torvalds -Sam Lantinga (slouken@cs.ucdavis.edu) 02/13/96 531da177e4SLinus Torvalds 541da177e4SLinus Torvalds */ 551da177e4SLinus Torvalds 561da177e4SLinus Torvalds /* Things I wish I had known when writing the tunnel driver: 571da177e4SLinus Torvalds 581da177e4SLinus Torvalds When the tunnel_xmit() function is called, the skb contains the 591da177e4SLinus Torvalds packet to be sent (plus a great deal of extra info), and dev 601da177e4SLinus Torvalds contains the tunnel device that _we_ are. 611da177e4SLinus Torvalds 621da177e4SLinus Torvalds When we are passed a packet, we are expected to fill in the 631da177e4SLinus Torvalds source address with our source IP address. 641da177e4SLinus Torvalds 651da177e4SLinus Torvalds What is the proper way to allocate, copy and free a buffer? 661da177e4SLinus Torvalds After you allocate it, it is a "0 length" chunk of memory 671da177e4SLinus Torvalds starting at zero. If you want to add headers to the buffer 681da177e4SLinus Torvalds later, you'll have to call "skb_reserve(skb, amount)" with 691da177e4SLinus Torvalds the amount of memory you want reserved. Then, you call 701da177e4SLinus Torvalds "skb_put(skb, amount)" with the amount of space you want in 711da177e4SLinus Torvalds the buffer. skb_put() returns a pointer to the top (#0) of 721da177e4SLinus Torvalds that buffer. skb->len is set to the amount of space you have 731da177e4SLinus Torvalds "allocated" with skb_put(). You can then write up to skb->len 741da177e4SLinus Torvalds bytes to that buffer. If you need more, you can call skb_put() 751da177e4SLinus Torvalds again with the additional amount of space you need. You can 761da177e4SLinus Torvalds find out how much more space you can allocate by calling 771da177e4SLinus Torvalds "skb_tailroom(skb)". 781da177e4SLinus Torvalds Now, to add header space, call "skb_push(skb, header_len)". 791da177e4SLinus Torvalds This creates space at the beginning of the buffer and returns 801da177e4SLinus Torvalds a pointer to this new space. If later you need to strip a 811da177e4SLinus Torvalds header from a buffer, call "skb_pull(skb, header_len)". 821da177e4SLinus Torvalds skb_headroom() will return how much space is left at the top 831da177e4SLinus Torvalds of the buffer (before the main data). Remember, this headroom 841da177e4SLinus Torvalds space must be reserved before the skb_put() function is called. 851da177e4SLinus Torvalds */ 861da177e4SLinus Torvalds 871da177e4SLinus Torvalds /* 881da177e4SLinus Torvalds This version of net/ipv4/ipip.c is cloned of net/ipv4/ip_gre.c 891da177e4SLinus Torvalds 901da177e4SLinus Torvalds For comments look at net/ipv4/ip_gre.c --ANK 911da177e4SLinus Torvalds */ 921da177e4SLinus Torvalds 931da177e4SLinus Torvalds 944fc268d2SRandy Dunlap #include <linux/capability.h> 951da177e4SLinus Torvalds #include <linux/module.h> 961da177e4SLinus Torvalds #include <linux/types.h> 971da177e4SLinus Torvalds #include <linux/kernel.h> 985a0e3ad6STejun Heo #include <linux/slab.h> 997c0f6ba6SLinus Torvalds #include <linux/uaccess.h> 1001da177e4SLinus Torvalds #include <linux/skbuff.h> 1011da177e4SLinus Torvalds #include <linux/netdevice.h> 1021da177e4SLinus Torvalds #include <linux/in.h> 1031da177e4SLinus Torvalds #include <linux/tcp.h> 1041da177e4SLinus Torvalds #include <linux/udp.h> 1051da177e4SLinus Torvalds #include <linux/if_arp.h> 1061da177e4SLinus Torvalds #include <linux/init.h> 1071da177e4SLinus Torvalds #include <linux/netfilter_ipv4.h> 10846f25dffSKris Katterjohn #include <linux/if_ether.h> 1091da177e4SLinus Torvalds 1101da177e4SLinus Torvalds #include <net/sock.h> 1111da177e4SLinus Torvalds #include <net/ip.h> 1121da177e4SLinus Torvalds #include <net/icmp.h> 113c5441932SPravin B Shelar #include <net/ip_tunnels.h> 1141da177e4SLinus Torvalds #include <net/inet_ecn.h> 1151da177e4SLinus Torvalds #include <net/xfrm.h> 11610dc4c7bSPavel Emelyanov #include <net/net_namespace.h> 11710dc4c7bSPavel Emelyanov #include <net/netns/generic.h> 118cfc7381bSAlexei Starovoitov #include <net/dst_metadata.h> 1191da177e4SLinus Torvalds 120eccc1bb8Sstephen hemminger static bool log_ecn_error = true; 121eccc1bb8Sstephen hemminger module_param(log_ecn_error, bool, 0644); 122eccc1bb8Sstephen hemminger MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN"); 123eccc1bb8Sstephen hemminger 124c7d03a00SAlexey Dobriyan static unsigned int ipip_net_id __read_mostly; 12510dc4c7bSPavel Emelyanov 1263c97af99SEric Dumazet static int ipip_tunnel_init(struct net_device *dev); 1270974658dSNicolas Dichtel static struct rtnl_link_ops ipip_link_ops __read_mostly; 1281da177e4SLinus Torvalds 129d2acc347SHerbert Xu static int ipip_err(struct sk_buff *skb, u32 info) 1301da177e4SLinus Torvalds { 1311da177e4SLinus Torvalds 132071f92d0SRami Rosen /* All the routers (except for Linux) return only 1331da177e4SLinus Torvalds 8 bytes of packet payload. It means, that precise relaying of 1341da177e4SLinus Torvalds ICMP in the real Internet is absolutely infeasible. 1351da177e4SLinus Torvalds */ 136fd58156eSPravin B Shelar struct net *net = dev_net(skb->dev); 137fd58156eSPravin B Shelar struct ip_tunnel_net *itn = net_generic(net, ipip_net_id); 138b71d1d42SEric Dumazet const struct iphdr *iph = (const struct iphdr *)skb->data; 1391da177e4SLinus Torvalds struct ip_tunnel *t; 140d2acc347SHerbert Xu int err; 141fd58156eSPravin B Shelar const int type = icmp_hdr(skb)->type; 142fd58156eSPravin B Shelar const int code = icmp_hdr(skb)->code; 1431da177e4SLinus Torvalds 144d2acc347SHerbert Xu err = -ENOENT; 145fd58156eSPravin B Shelar t = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY, 146fd58156eSPravin B Shelar iph->daddr, iph->saddr, 0); 14751456b29SIan Morris if (!t) 14836393395SDavid S. Miller goto out; 14936393395SDavid S. Miller 15036393395SDavid S. Miller if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) { 15136393395SDavid S. Miller ipv4_update_pmtu(skb, dev_net(skb->dev), info, 1521b69e7e6SSimon Horman t->parms.link, 0, iph->protocol, 0); 15336393395SDavid S. Miller err = 0; 15436393395SDavid S. Miller goto out; 15536393395SDavid S. Miller } 15636393395SDavid S. Miller 15755be7a9cSDavid S. Miller if (type == ICMP_REDIRECT) { 1582346829eSDmitry Popov ipv4_redirect(skb, dev_net(skb->dev), t->parms.link, 0, 1591b69e7e6SSimon Horman iph->protocol, 0); 16055be7a9cSDavid S. Miller err = 0; 16155be7a9cSDavid S. Miller goto out; 16255be7a9cSDavid S. Miller } 16355be7a9cSDavid S. Miller 16436393395SDavid S. Miller if (t->parms.iph.daddr == 0) 1651da177e4SLinus Torvalds goto out; 166d2acc347SHerbert Xu 167d2acc347SHerbert Xu err = 0; 1681da177e4SLinus Torvalds if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED) 1691da177e4SLinus Torvalds goto out; 1701da177e4SLinus Torvalds 17126d94b46SWei Yongjun if (time_before(jiffies, t->err_time + IPTUNNEL_ERR_TIMEO)) 1721da177e4SLinus Torvalds t->err_count++; 1731da177e4SLinus Torvalds else 1741da177e4SLinus Torvalds t->err_count = 1; 1751da177e4SLinus Torvalds t->err_time = jiffies; 176b0558ef2Sstephen hemminger 177fd58156eSPravin B Shelar out: 178d2acc347SHerbert Xu return err; 1791da177e4SLinus Torvalds } 1801da177e4SLinus Torvalds 1811b69e7e6SSimon Horman static const struct tnl_ptk_info ipip_tpi = { 182fd58156eSPravin B Shelar /* no tunnel info required for ipip. */ 183fd58156eSPravin B Shelar .proto = htons(ETH_P_IP), 184fd58156eSPravin B Shelar }; 185fd58156eSPravin B Shelar 1861b69e7e6SSimon Horman #if IS_ENABLED(CONFIG_MPLS) 1871b69e7e6SSimon Horman static const struct tnl_ptk_info mplsip_tpi = { 1881b69e7e6SSimon Horman /* no tunnel info required for mplsip. */ 1891b69e7e6SSimon Horman .proto = htons(ETH_P_MPLS_UC), 1901b69e7e6SSimon Horman }; 1911b69e7e6SSimon Horman #endif 1921b69e7e6SSimon Horman 1931b69e7e6SSimon Horman static int ipip_tunnel_rcv(struct sk_buff *skb, u8 ipproto) 1941da177e4SLinus Torvalds { 195fd58156eSPravin B Shelar struct net *net = dev_net(skb->dev); 196fd58156eSPravin B Shelar struct ip_tunnel_net *itn = net_generic(net, ipip_net_id); 197cfc7381bSAlexei Starovoitov struct metadata_dst *tun_dst = NULL; 1981da177e4SLinus Torvalds struct ip_tunnel *tunnel; 1993d7b46cdSPravin B Shelar const struct iphdr *iph; 2001da177e4SLinus Torvalds 2013d7b46cdSPravin B Shelar iph = ip_hdr(skb); 202fd58156eSPravin B Shelar tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY, 203fd58156eSPravin B Shelar iph->saddr, iph->daddr, 0); 204fd58156eSPravin B Shelar if (tunnel) { 2051b69e7e6SSimon Horman const struct tnl_ptk_info *tpi; 2061b69e7e6SSimon Horman 2071b69e7e6SSimon Horman if (tunnel->parms.iph.protocol != ipproto && 2081b69e7e6SSimon Horman tunnel->parms.iph.protocol != 0) 2091b69e7e6SSimon Horman goto drop; 2101b69e7e6SSimon Horman 211eccc1bb8Sstephen hemminger if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) 212eccc1bb8Sstephen hemminger goto drop; 2131b69e7e6SSimon Horman #if IS_ENABLED(CONFIG_MPLS) 2141b69e7e6SSimon Horman if (ipproto == IPPROTO_MPLS) 2151b69e7e6SSimon Horman tpi = &mplsip_tpi; 2161b69e7e6SSimon Horman else 2171b69e7e6SSimon Horman #endif 2181b69e7e6SSimon Horman tpi = &ipip_tpi; 2191b69e7e6SSimon Horman if (iptunnel_pull_header(skb, 0, tpi->proto, false)) 220737e828bSLi Hongjun goto drop; 221cfc7381bSAlexei Starovoitov if (tunnel->collect_md) { 222cfc7381bSAlexei Starovoitov tun_dst = ip_tun_rx_dst(skb, 0, 0, 0); 223cfc7381bSAlexei Starovoitov if (!tun_dst) 224cfc7381bSAlexei Starovoitov return 0; 225cfc7381bSAlexei Starovoitov } 226cfc7381bSAlexei Starovoitov return ip_tunnel_rcv(tunnel, skb, tpi, tun_dst, log_ecn_error); 2271da177e4SLinus Torvalds } 2281da177e4SLinus Torvalds 2291da177e4SLinus Torvalds return -1; 230eccc1bb8Sstephen hemminger 231eccc1bb8Sstephen hemminger drop: 232eccc1bb8Sstephen hemminger kfree_skb(skb); 233eccc1bb8Sstephen hemminger return 0; 2341da177e4SLinus Torvalds } 2351da177e4SLinus Torvalds 2361b69e7e6SSimon Horman static int ipip_rcv(struct sk_buff *skb) 2371b69e7e6SSimon Horman { 2381b69e7e6SSimon Horman return ipip_tunnel_rcv(skb, IPPROTO_IPIP); 2391b69e7e6SSimon Horman } 2401b69e7e6SSimon Horman 2411b69e7e6SSimon Horman #if IS_ENABLED(CONFIG_MPLS) 2421b69e7e6SSimon Horman static int mplsip_rcv(struct sk_buff *skb) 2431b69e7e6SSimon Horman { 2441b69e7e6SSimon Horman return ipip_tunnel_rcv(skb, IPPROTO_MPLS); 2451b69e7e6SSimon Horman } 2461b69e7e6SSimon Horman #endif 2471b69e7e6SSimon Horman 2481da177e4SLinus Torvalds /* 2491da177e4SLinus Torvalds * This function assumes it is being called from dev_queue_xmit() 2501da177e4SLinus Torvalds * and that skb is filled properly by that function. 2511da177e4SLinus Torvalds */ 2521b69e7e6SSimon Horman static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, 2531b69e7e6SSimon Horman struct net_device *dev) 2541da177e4SLinus Torvalds { 2552941a486SPatrick McHardy struct ip_tunnel *tunnel = netdev_priv(dev); 256b71d1d42SEric Dumazet const struct iphdr *tiph = &tunnel->parms.iph; 2571b69e7e6SSimon Horman u8 ipproto; 2581da177e4SLinus Torvalds 2591b69e7e6SSimon Horman switch (skb->protocol) { 2601b69e7e6SSimon Horman case htons(ETH_P_IP): 2611b69e7e6SSimon Horman ipproto = IPPROTO_IPIP; 2621b69e7e6SSimon Horman break; 2631b69e7e6SSimon Horman #if IS_ENABLED(CONFIG_MPLS) 2641b69e7e6SSimon Horman case htons(ETH_P_MPLS_UC): 2651b69e7e6SSimon Horman ipproto = IPPROTO_MPLS; 2661b69e7e6SSimon Horman break; 2671b69e7e6SSimon Horman #endif 2681b69e7e6SSimon Horman default: 2691b69e7e6SSimon Horman goto tx_error; 2701b69e7e6SSimon Horman } 2711b69e7e6SSimon Horman 2721b69e7e6SSimon Horman if (tiph->protocol != ipproto && tiph->protocol != 0) 2731da177e4SLinus Torvalds goto tx_error; 274cef401deSEric Dumazet 2757e13318dSTom Herbert if (iptunnel_handle_offloads(skb, SKB_GSO_IPXIP4)) 276aed069dfSAlexander Duyck goto tx_error; 2774f3ed920SPravin B Shelar 2781b69e7e6SSimon Horman skb_set_inner_ipproto(skb, ipproto); 279077c5a09STom Herbert 280cfc7381bSAlexei Starovoitov if (tunnel->collect_md) 281cfc7381bSAlexei Starovoitov ip_md_tunnel_xmit(skb, dev, ipproto); 282cfc7381bSAlexei Starovoitov else 2831b69e7e6SSimon Horman ip_tunnel_xmit(skb, dev, tiph, ipproto); 2846ed10654SPatrick McHardy return NETDEV_TX_OK; 2851da177e4SLinus Torvalds 2861da177e4SLinus Torvalds tx_error: 2873acfa1e7SEric Dumazet kfree_skb(skb); 288aed069dfSAlexander Duyck 289cb32f511SEric Dumazet dev->stats.tx_errors++; 2906ed10654SPatrick McHardy return NETDEV_TX_OK; 2911da177e4SLinus Torvalds } 2921da177e4SLinus Torvalds 2931b69e7e6SSimon Horman static bool ipip_tunnel_ioctl_verify_protocol(u8 ipproto) 2941b69e7e6SSimon Horman { 2951b69e7e6SSimon Horman switch (ipproto) { 2961b69e7e6SSimon Horman case 0: 2971b69e7e6SSimon Horman case IPPROTO_IPIP: 2981b69e7e6SSimon Horman #if IS_ENABLED(CONFIG_MPLS) 2991b69e7e6SSimon Horman case IPPROTO_MPLS: 3001b69e7e6SSimon Horman #endif 3011b69e7e6SSimon Horman return true; 3021b69e7e6SSimon Horman } 3031b69e7e6SSimon Horman 3041b69e7e6SSimon Horman return false; 3051b69e7e6SSimon Horman } 3061b69e7e6SSimon Horman 3071da177e4SLinus Torvalds static int 3081da177e4SLinus Torvalds ipip_tunnel_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) 3091da177e4SLinus Torvalds { 3101da177e4SLinus Torvalds int err = 0; 3111da177e4SLinus Torvalds struct ip_tunnel_parm p; 3121da177e4SLinus Torvalds 3131da177e4SLinus Torvalds if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) 314fd58156eSPravin B Shelar return -EFAULT; 3151da177e4SLinus Torvalds 3163b7b514fSCong Wang if (cmd == SIOCADDTUNNEL || cmd == SIOCCHGTUNNEL) { 3171b69e7e6SSimon Horman if (p.iph.version != 4 || 3181b69e7e6SSimon Horman !ipip_tunnel_ioctl_verify_protocol(p.iph.protocol) || 3191da177e4SLinus Torvalds p.iph.ihl != 5 || (p.iph.frag_off&htons(~IP_DF))) 320fd58156eSPravin B Shelar return -EINVAL; 3213b7b514fSCong Wang } 3223b7b514fSCong Wang 323252a8fbeSEric Dumazet p.i_key = p.o_key = 0; 324252a8fbeSEric Dumazet p.i_flags = p.o_flags = 0; 325fd58156eSPravin B Shelar err = ip_tunnel_ioctl(dev, &p, cmd); 326fd58156eSPravin B Shelar if (err) 3271da177e4SLinus Torvalds return err; 3281da177e4SLinus Torvalds 329fd58156eSPravin B Shelar if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p))) 330fd58156eSPravin B Shelar return -EFAULT; 331fd58156eSPravin B Shelar 3321da177e4SLinus Torvalds return 0; 3331da177e4SLinus Torvalds } 3341da177e4SLinus Torvalds 33523a12b14SStephen Hemminger static const struct net_device_ops ipip_netdev_ops = { 336fd58156eSPravin B Shelar .ndo_init = ipip_tunnel_init, 337fd58156eSPravin B Shelar .ndo_uninit = ip_tunnel_uninit, 33823a12b14SStephen Hemminger .ndo_start_xmit = ipip_tunnel_xmit, 33923a12b14SStephen Hemminger .ndo_do_ioctl = ipip_tunnel_ioctl, 340fd58156eSPravin B Shelar .ndo_change_mtu = ip_tunnel_change_mtu, 341fd58156eSPravin B Shelar .ndo_get_stats64 = ip_tunnel_get_stats64, 3421e99584bSNicolas Dichtel .ndo_get_iflink = ip_tunnel_get_iflink, 34323a12b14SStephen Hemminger }; 34423a12b14SStephen Hemminger 345c3b89fbbSEric Dumazet #define IPIP_FEATURES (NETIF_F_SG | \ 346c3b89fbbSEric Dumazet NETIF_F_FRAGLIST | \ 347c3b89fbbSEric Dumazet NETIF_F_HIGHDMA | \ 348cb32f511SEric Dumazet NETIF_F_GSO_SOFTWARE | \ 349c3b89fbbSEric Dumazet NETIF_F_HW_CSUM) 350c3b89fbbSEric Dumazet 3511da177e4SLinus Torvalds static void ipip_tunnel_setup(struct net_device *dev) 3521da177e4SLinus Torvalds { 35323a12b14SStephen Hemminger dev->netdev_ops = &ipip_netdev_ops; 3541da177e4SLinus Torvalds 3551da177e4SLinus Torvalds dev->type = ARPHRD_TUNNEL; 3561da177e4SLinus Torvalds dev->flags = IFF_NOARP; 3571da177e4SLinus Torvalds dev->addr_len = 4; 358153f0943SEric Dumazet dev->features |= NETIF_F_LLTX; 35902875878SEric Dumazet netif_keep_dst(dev); 360c3b89fbbSEric Dumazet 361c3b89fbbSEric Dumazet dev->features |= IPIP_FEATURES; 362c3b89fbbSEric Dumazet dev->hw_features |= IPIP_FEATURES; 363fd58156eSPravin B Shelar ip_tunnel_setup(dev, ipip_net_id); 3641da177e4SLinus Torvalds } 3651da177e4SLinus Torvalds 3663c97af99SEric Dumazet static int ipip_tunnel_init(struct net_device *dev) 3671da177e4SLinus Torvalds { 36823a12b14SStephen Hemminger struct ip_tunnel *tunnel = netdev_priv(dev); 3691da177e4SLinus Torvalds 3701da177e4SLinus Torvalds memcpy(dev->dev_addr, &tunnel->parms.iph.saddr, 4); 3711da177e4SLinus Torvalds memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4); 3721da177e4SLinus Torvalds 373473ab820STom Herbert tunnel->tun_hlen = 0; 374473ab820STom Herbert tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen; 375fd58156eSPravin B Shelar return ip_tunnel_init(dev); 3761da177e4SLinus Torvalds } 3771da177e4SLinus Torvalds 378a8b8a889SMatthias Schiffer static int ipip_tunnel_validate(struct nlattr *tb[], struct nlattr *data[], 379a8b8a889SMatthias Schiffer struct netlink_ext_ack *extack) 3801b69e7e6SSimon Horman { 3811b69e7e6SSimon Horman u8 proto; 3821b69e7e6SSimon Horman 3831b69e7e6SSimon Horman if (!data || !data[IFLA_IPTUN_PROTO]) 3841b69e7e6SSimon Horman return 0; 3851b69e7e6SSimon Horman 3861b69e7e6SSimon Horman proto = nla_get_u8(data[IFLA_IPTUN_PROTO]); 3871b69e7e6SSimon Horman if (proto != IPPROTO_IPIP && proto != IPPROTO_MPLS && proto != 0) 3881b69e7e6SSimon Horman return -EINVAL; 3891b69e7e6SSimon Horman 3901b69e7e6SSimon Horman return 0; 3911b69e7e6SSimon Horman } 3921b69e7e6SSimon Horman 393be42da0eSNicolas Dichtel static void ipip_netlink_parms(struct nlattr *data[], 3949830ad4cSCraig Gallek struct ip_tunnel_parm *parms, bool *collect_md, 3959830ad4cSCraig Gallek __u32 *fwmark) 396be42da0eSNicolas Dichtel { 397be42da0eSNicolas Dichtel memset(parms, 0, sizeof(*parms)); 398be42da0eSNicolas Dichtel 399be42da0eSNicolas Dichtel parms->iph.version = 4; 400be42da0eSNicolas Dichtel parms->iph.protocol = IPPROTO_IPIP; 401be42da0eSNicolas Dichtel parms->iph.ihl = 5; 402cfc7381bSAlexei Starovoitov *collect_md = false; 403be42da0eSNicolas Dichtel 404be42da0eSNicolas Dichtel if (!data) 405be42da0eSNicolas Dichtel return; 406be42da0eSNicolas Dichtel 407be42da0eSNicolas Dichtel if (data[IFLA_IPTUN_LINK]) 408be42da0eSNicolas Dichtel parms->link = nla_get_u32(data[IFLA_IPTUN_LINK]); 409be42da0eSNicolas Dichtel 410be42da0eSNicolas Dichtel if (data[IFLA_IPTUN_LOCAL]) 41167b61f6cSJiri Benc parms->iph.saddr = nla_get_in_addr(data[IFLA_IPTUN_LOCAL]); 412be42da0eSNicolas Dichtel 413be42da0eSNicolas Dichtel if (data[IFLA_IPTUN_REMOTE]) 41467b61f6cSJiri Benc parms->iph.daddr = nla_get_in_addr(data[IFLA_IPTUN_REMOTE]); 415be42da0eSNicolas Dichtel 416be42da0eSNicolas Dichtel if (data[IFLA_IPTUN_TTL]) { 417be42da0eSNicolas Dichtel parms->iph.ttl = nla_get_u8(data[IFLA_IPTUN_TTL]); 418be42da0eSNicolas Dichtel if (parms->iph.ttl) 419be42da0eSNicolas Dichtel parms->iph.frag_off = htons(IP_DF); 420be42da0eSNicolas Dichtel } 421be42da0eSNicolas Dichtel 422be42da0eSNicolas Dichtel if (data[IFLA_IPTUN_TOS]) 423be42da0eSNicolas Dichtel parms->iph.tos = nla_get_u8(data[IFLA_IPTUN_TOS]); 424be42da0eSNicolas Dichtel 4251b69e7e6SSimon Horman if (data[IFLA_IPTUN_PROTO]) 4261b69e7e6SSimon Horman parms->iph.protocol = nla_get_u8(data[IFLA_IPTUN_PROTO]); 4271b69e7e6SSimon Horman 428be42da0eSNicolas Dichtel if (!data[IFLA_IPTUN_PMTUDISC] || nla_get_u8(data[IFLA_IPTUN_PMTUDISC])) 429be42da0eSNicolas Dichtel parms->iph.frag_off = htons(IP_DF); 430cfc7381bSAlexei Starovoitov 431cfc7381bSAlexei Starovoitov if (data[IFLA_IPTUN_COLLECT_METADATA]) 432cfc7381bSAlexei Starovoitov *collect_md = true; 4339830ad4cSCraig Gallek 4349830ad4cSCraig Gallek if (data[IFLA_IPTUN_FWMARK]) 4359830ad4cSCraig Gallek *fwmark = nla_get_u32(data[IFLA_IPTUN_FWMARK]); 436be42da0eSNicolas Dichtel } 437be42da0eSNicolas Dichtel 438473ab820STom Herbert /* This function returns true when ENCAP attributes are present in the nl msg */ 439473ab820STom Herbert static bool ipip_netlink_encap_parms(struct nlattr *data[], 440473ab820STom Herbert struct ip_tunnel_encap *ipencap) 441473ab820STom Herbert { 442473ab820STom Herbert bool ret = false; 443473ab820STom Herbert 444473ab820STom Herbert memset(ipencap, 0, sizeof(*ipencap)); 445473ab820STom Herbert 446473ab820STom Herbert if (!data) 447473ab820STom Herbert return ret; 448473ab820STom Herbert 449473ab820STom Herbert if (data[IFLA_IPTUN_ENCAP_TYPE]) { 450473ab820STom Herbert ret = true; 451473ab820STom Herbert ipencap->type = nla_get_u16(data[IFLA_IPTUN_ENCAP_TYPE]); 452473ab820STom Herbert } 453473ab820STom Herbert 454473ab820STom Herbert if (data[IFLA_IPTUN_ENCAP_FLAGS]) { 455473ab820STom Herbert ret = true; 456473ab820STom Herbert ipencap->flags = nla_get_u16(data[IFLA_IPTUN_ENCAP_FLAGS]); 457473ab820STom Herbert } 458473ab820STom Herbert 459473ab820STom Herbert if (data[IFLA_IPTUN_ENCAP_SPORT]) { 460473ab820STom Herbert ret = true; 4613e97fa70SSabrina Dubroca ipencap->sport = nla_get_be16(data[IFLA_IPTUN_ENCAP_SPORT]); 462473ab820STom Herbert } 463473ab820STom Herbert 464473ab820STom Herbert if (data[IFLA_IPTUN_ENCAP_DPORT]) { 465473ab820STom Herbert ret = true; 4663e97fa70SSabrina Dubroca ipencap->dport = nla_get_be16(data[IFLA_IPTUN_ENCAP_DPORT]); 467473ab820STom Herbert } 468473ab820STom Herbert 469473ab820STom Herbert return ret; 470473ab820STom Herbert } 471473ab820STom Herbert 472be42da0eSNicolas Dichtel static int ipip_newlink(struct net *src_net, struct net_device *dev, 4737a3f4a18SMatthias Schiffer struct nlattr *tb[], struct nlattr *data[], 4747a3f4a18SMatthias Schiffer struct netlink_ext_ack *extack) 475be42da0eSNicolas Dichtel { 476cfc7381bSAlexei Starovoitov struct ip_tunnel *t = netdev_priv(dev); 477fd58156eSPravin B Shelar struct ip_tunnel_parm p; 478473ab820STom Herbert struct ip_tunnel_encap ipencap; 4799830ad4cSCraig Gallek __u32 fwmark = 0; 480473ab820STom Herbert 481473ab820STom Herbert if (ipip_netlink_encap_parms(data, &ipencap)) { 482473ab820STom Herbert int err = ip_tunnel_encap_setup(t, &ipencap); 483473ab820STom Herbert 484473ab820STom Herbert if (err < 0) 485473ab820STom Herbert return err; 486473ab820STom Herbert } 487be42da0eSNicolas Dichtel 4889830ad4cSCraig Gallek ipip_netlink_parms(data, &p, &t->collect_md, &fwmark); 4899830ad4cSCraig Gallek return ip_tunnel_newlink(dev, tb, &p, fwmark); 490be42da0eSNicolas Dichtel } 491be42da0eSNicolas Dichtel 492be42da0eSNicolas Dichtel static int ipip_changelink(struct net_device *dev, struct nlattr *tb[], 493ad744b22SMatthias Schiffer struct nlattr *data[], 494ad744b22SMatthias Schiffer struct netlink_ext_ack *extack) 495be42da0eSNicolas Dichtel { 4969830ad4cSCraig Gallek struct ip_tunnel *t = netdev_priv(dev); 497be42da0eSNicolas Dichtel struct ip_tunnel_parm p; 498473ab820STom Herbert struct ip_tunnel_encap ipencap; 499cfc7381bSAlexei Starovoitov bool collect_md; 5009830ad4cSCraig Gallek __u32 fwmark = t->fwmark; 501473ab820STom Herbert 502473ab820STom Herbert if (ipip_netlink_encap_parms(data, &ipencap)) { 503473ab820STom Herbert int err = ip_tunnel_encap_setup(t, &ipencap); 504473ab820STom Herbert 505473ab820STom Herbert if (err < 0) 506473ab820STom Herbert return err; 507473ab820STom Herbert } 508be42da0eSNicolas Dichtel 5099830ad4cSCraig Gallek ipip_netlink_parms(data, &p, &collect_md, &fwmark); 510cfc7381bSAlexei Starovoitov if (collect_md) 511cfc7381bSAlexei Starovoitov return -EINVAL; 512be42da0eSNicolas Dichtel 513be42da0eSNicolas Dichtel if (((dev->flags & IFF_POINTOPOINT) && !p.iph.daddr) || 514be42da0eSNicolas Dichtel (!(dev->flags & IFF_POINTOPOINT) && p.iph.daddr)) 515be42da0eSNicolas Dichtel return -EINVAL; 516be42da0eSNicolas Dichtel 5179830ad4cSCraig Gallek return ip_tunnel_changelink(dev, tb, &p, fwmark); 518be42da0eSNicolas Dichtel } 519be42da0eSNicolas Dichtel 5200974658dSNicolas Dichtel static size_t ipip_get_size(const struct net_device *dev) 5210974658dSNicolas Dichtel { 5220974658dSNicolas Dichtel return 5230974658dSNicolas Dichtel /* IFLA_IPTUN_LINK */ 5240974658dSNicolas Dichtel nla_total_size(4) + 5250974658dSNicolas Dichtel /* IFLA_IPTUN_LOCAL */ 5260974658dSNicolas Dichtel nla_total_size(4) + 5270974658dSNicolas Dichtel /* IFLA_IPTUN_REMOTE */ 5280974658dSNicolas Dichtel nla_total_size(4) + 5290974658dSNicolas Dichtel /* IFLA_IPTUN_TTL */ 5300974658dSNicolas Dichtel nla_total_size(1) + 5310974658dSNicolas Dichtel /* IFLA_IPTUN_TOS */ 5320974658dSNicolas Dichtel nla_total_size(1) + 5331b69e7e6SSimon Horman /* IFLA_IPTUN_PROTO */ 5341b69e7e6SSimon Horman nla_total_size(1) + 535befe2aa1SNicolas Dichtel /* IFLA_IPTUN_PMTUDISC */ 536befe2aa1SNicolas Dichtel nla_total_size(1) + 537473ab820STom Herbert /* IFLA_IPTUN_ENCAP_TYPE */ 538473ab820STom Herbert nla_total_size(2) + 539473ab820STom Herbert /* IFLA_IPTUN_ENCAP_FLAGS */ 540473ab820STom Herbert nla_total_size(2) + 541473ab820STom Herbert /* IFLA_IPTUN_ENCAP_SPORT */ 542473ab820STom Herbert nla_total_size(2) + 543473ab820STom Herbert /* IFLA_IPTUN_ENCAP_DPORT */ 544473ab820STom Herbert nla_total_size(2) + 545cfc7381bSAlexei Starovoitov /* IFLA_IPTUN_COLLECT_METADATA */ 546cfc7381bSAlexei Starovoitov nla_total_size(0) + 5479830ad4cSCraig Gallek /* IFLA_IPTUN_FWMARK */ 5489830ad4cSCraig Gallek nla_total_size(4) + 5490974658dSNicolas Dichtel 0; 5500974658dSNicolas Dichtel } 5510974658dSNicolas Dichtel 5520974658dSNicolas Dichtel static int ipip_fill_info(struct sk_buff *skb, const struct net_device *dev) 5530974658dSNicolas Dichtel { 5540974658dSNicolas Dichtel struct ip_tunnel *tunnel = netdev_priv(dev); 5550974658dSNicolas Dichtel struct ip_tunnel_parm *parm = &tunnel->parms; 5560974658dSNicolas Dichtel 5570974658dSNicolas Dichtel if (nla_put_u32(skb, IFLA_IPTUN_LINK, parm->link) || 558930345eaSJiri Benc nla_put_in_addr(skb, IFLA_IPTUN_LOCAL, parm->iph.saddr) || 559930345eaSJiri Benc nla_put_in_addr(skb, IFLA_IPTUN_REMOTE, parm->iph.daddr) || 5600974658dSNicolas Dichtel nla_put_u8(skb, IFLA_IPTUN_TTL, parm->iph.ttl) || 561befe2aa1SNicolas Dichtel nla_put_u8(skb, IFLA_IPTUN_TOS, parm->iph.tos) || 5621b69e7e6SSimon Horman nla_put_u8(skb, IFLA_IPTUN_PROTO, parm->iph.protocol) || 563befe2aa1SNicolas Dichtel nla_put_u8(skb, IFLA_IPTUN_PMTUDISC, 5649830ad4cSCraig Gallek !!(parm->iph.frag_off & htons(IP_DF))) || 5659830ad4cSCraig Gallek nla_put_u32(skb, IFLA_IPTUN_FWMARK, tunnel->fwmark)) 5660974658dSNicolas Dichtel goto nla_put_failure; 567473ab820STom Herbert 568473ab820STom Herbert if (nla_put_u16(skb, IFLA_IPTUN_ENCAP_TYPE, 569473ab820STom Herbert tunnel->encap.type) || 5703e97fa70SSabrina Dubroca nla_put_be16(skb, IFLA_IPTUN_ENCAP_SPORT, 571473ab820STom Herbert tunnel->encap.sport) || 5723e97fa70SSabrina Dubroca nla_put_be16(skb, IFLA_IPTUN_ENCAP_DPORT, 573473ab820STom Herbert tunnel->encap.dport) || 574473ab820STom Herbert nla_put_u16(skb, IFLA_IPTUN_ENCAP_FLAGS, 575e1b2cb65STom Herbert tunnel->encap.flags)) 576473ab820STom Herbert goto nla_put_failure; 577473ab820STom Herbert 578cfc7381bSAlexei Starovoitov if (tunnel->collect_md) 579cfc7381bSAlexei Starovoitov if (nla_put_flag(skb, IFLA_IPTUN_COLLECT_METADATA)) 580cfc7381bSAlexei Starovoitov goto nla_put_failure; 5810974658dSNicolas Dichtel return 0; 5820974658dSNicolas Dichtel 5830974658dSNicolas Dichtel nla_put_failure: 5840974658dSNicolas Dichtel return -EMSGSIZE; 5850974658dSNicolas Dichtel } 5860974658dSNicolas Dichtel 587be42da0eSNicolas Dichtel static const struct nla_policy ipip_policy[IFLA_IPTUN_MAX + 1] = { 588be42da0eSNicolas Dichtel [IFLA_IPTUN_LINK] = { .type = NLA_U32 }, 589be42da0eSNicolas Dichtel [IFLA_IPTUN_LOCAL] = { .type = NLA_U32 }, 590be42da0eSNicolas Dichtel [IFLA_IPTUN_REMOTE] = { .type = NLA_U32 }, 591be42da0eSNicolas Dichtel [IFLA_IPTUN_TTL] = { .type = NLA_U8 }, 592be42da0eSNicolas Dichtel [IFLA_IPTUN_TOS] = { .type = NLA_U8 }, 5931b69e7e6SSimon Horman [IFLA_IPTUN_PROTO] = { .type = NLA_U8 }, 594be42da0eSNicolas Dichtel [IFLA_IPTUN_PMTUDISC] = { .type = NLA_U8 }, 595473ab820STom Herbert [IFLA_IPTUN_ENCAP_TYPE] = { .type = NLA_U16 }, 596473ab820STom Herbert [IFLA_IPTUN_ENCAP_FLAGS] = { .type = NLA_U16 }, 597473ab820STom Herbert [IFLA_IPTUN_ENCAP_SPORT] = { .type = NLA_U16 }, 598473ab820STom Herbert [IFLA_IPTUN_ENCAP_DPORT] = { .type = NLA_U16 }, 599cfc7381bSAlexei Starovoitov [IFLA_IPTUN_COLLECT_METADATA] = { .type = NLA_FLAG }, 6009830ad4cSCraig Gallek [IFLA_IPTUN_FWMARK] = { .type = NLA_U32 }, 601be42da0eSNicolas Dichtel }; 602be42da0eSNicolas Dichtel 6030974658dSNicolas Dichtel static struct rtnl_link_ops ipip_link_ops __read_mostly = { 6040974658dSNicolas Dichtel .kind = "ipip", 6050974658dSNicolas Dichtel .maxtype = IFLA_IPTUN_MAX, 606be42da0eSNicolas Dichtel .policy = ipip_policy, 6070974658dSNicolas Dichtel .priv_size = sizeof(struct ip_tunnel), 608be42da0eSNicolas Dichtel .setup = ipip_tunnel_setup, 6091b69e7e6SSimon Horman .validate = ipip_tunnel_validate, 610be42da0eSNicolas Dichtel .newlink = ipip_newlink, 611be42da0eSNicolas Dichtel .changelink = ipip_changelink, 612fd58156eSPravin B Shelar .dellink = ip_tunnel_dellink, 6130974658dSNicolas Dichtel .get_size = ipip_get_size, 6140974658dSNicolas Dichtel .fill_info = ipip_fill_info, 6151728d4faSNicolas Dichtel .get_link_net = ip_tunnel_get_link_net, 6160974658dSNicolas Dichtel }; 6170974658dSNicolas Dichtel 6186dcd814bSEric Dumazet static struct xfrm_tunnel ipip_handler __read_mostly = { 6191da177e4SLinus Torvalds .handler = ipip_rcv, 6201da177e4SLinus Torvalds .err_handler = ipip_err, 621d2acc347SHerbert Xu .priority = 1, 6221da177e4SLinus Torvalds }; 6231da177e4SLinus Torvalds 6241b69e7e6SSimon Horman #if IS_ENABLED(CONFIG_MPLS) 6251b69e7e6SSimon Horman static struct xfrm_tunnel mplsip_handler __read_mostly = { 6261b69e7e6SSimon Horman .handler = mplsip_rcv, 6271b69e7e6SSimon Horman .err_handler = ipip_err, 6281b69e7e6SSimon Horman .priority = 1, 6291b69e7e6SSimon Horman }; 6301b69e7e6SSimon Horman #endif 6311b69e7e6SSimon Horman 6322c8c1e72SAlexey Dobriyan static int __net_init ipip_init_net(struct net *net) 63310dc4c7bSPavel Emelyanov { 634fd58156eSPravin B Shelar return ip_tunnel_init_net(net, ipip_net_id, &ipip_link_ops, "tunl0"); 63510dc4c7bSPavel Emelyanov } 63610dc4c7bSPavel Emelyanov 637*64bc1781SEric Dumazet static void __net_exit ipip_exit_batch_net(struct list_head *list_net) 63810dc4c7bSPavel Emelyanov { 639*64bc1781SEric Dumazet ip_tunnel_delete_nets(list_net, ipip_net_id, &ipip_link_ops); 64010dc4c7bSPavel Emelyanov } 64110dc4c7bSPavel Emelyanov 64210dc4c7bSPavel Emelyanov static struct pernet_operations ipip_net_ops = { 64310dc4c7bSPavel Emelyanov .init = ipip_init_net, 644*64bc1781SEric Dumazet .exit_batch = ipip_exit_batch_net, 64586de8a63SEric W. Biederman .id = &ipip_net_id, 646fd58156eSPravin B Shelar .size = sizeof(struct ip_tunnel_net), 64710dc4c7bSPavel Emelyanov }; 64810dc4c7bSPavel Emelyanov 6491da177e4SLinus Torvalds static int __init ipip_init(void) 6501da177e4SLinus Torvalds { 6511da177e4SLinus Torvalds int err; 6521da177e4SLinus Torvalds 6531b69e7e6SSimon Horman pr_info("ipip: IPv4 and MPLS over IPv4 tunneling driver\n"); 6541da177e4SLinus Torvalds 65586de8a63SEric W. Biederman err = register_pernet_device(&ipip_net_ops); 656d5aa407fSAlexey Dobriyan if (err < 0) 657d5aa407fSAlexey Dobriyan return err; 658d5aa407fSAlexey Dobriyan err = xfrm4_tunnel_register(&ipip_handler, AF_INET); 659d5aa407fSAlexey Dobriyan if (err < 0) { 660058bd4d2SJoe Perches pr_info("%s: can't register tunnel\n", __func__); 6611b69e7e6SSimon Horman goto xfrm_tunnel_ipip_failed; 662d5aa407fSAlexey Dobriyan } 6631b69e7e6SSimon Horman #if IS_ENABLED(CONFIG_MPLS) 6641b69e7e6SSimon Horman err = xfrm4_tunnel_register(&mplsip_handler, AF_MPLS); 6651b69e7e6SSimon Horman if (err < 0) { 6661b69e7e6SSimon Horman pr_info("%s: can't register tunnel\n", __func__); 6671b69e7e6SSimon Horman goto xfrm_tunnel_mplsip_failed; 6681b69e7e6SSimon Horman } 6691b69e7e6SSimon Horman #endif 6700974658dSNicolas Dichtel err = rtnl_link_register(&ipip_link_ops); 6710974658dSNicolas Dichtel if (err < 0) 6720974658dSNicolas Dichtel goto rtnl_link_failed; 6730974658dSNicolas Dichtel 6740974658dSNicolas Dichtel out: 675b9855c54SPavel Emelyanov return err; 6760974658dSNicolas Dichtel 6770974658dSNicolas Dichtel rtnl_link_failed: 6781b69e7e6SSimon Horman #if IS_ENABLED(CONFIG_MPLS) 6791b69e7e6SSimon Horman xfrm4_tunnel_deregister(&mplsip_handler, AF_INET); 6801b69e7e6SSimon Horman xfrm_tunnel_mplsip_failed: 6811b69e7e6SSimon Horman 6821b69e7e6SSimon Horman #endif 6830974658dSNicolas Dichtel xfrm4_tunnel_deregister(&ipip_handler, AF_INET); 6841b69e7e6SSimon Horman xfrm_tunnel_ipip_failed: 6850974658dSNicolas Dichtel unregister_pernet_device(&ipip_net_ops); 6860974658dSNicolas Dichtel goto out; 6871da177e4SLinus Torvalds } 6881da177e4SLinus Torvalds 6891da177e4SLinus Torvalds static void __exit ipip_fini(void) 6901da177e4SLinus Torvalds { 6910974658dSNicolas Dichtel rtnl_link_unregister(&ipip_link_ops); 692c0d56408SKazunori MIYAZAWA if (xfrm4_tunnel_deregister(&ipip_handler, AF_INET)) 693058bd4d2SJoe Perches pr_info("%s: can't deregister tunnel\n", __func__); 6941b69e7e6SSimon Horman #if IS_ENABLED(CONFIG_MPLS) 6951b69e7e6SSimon Horman if (xfrm4_tunnel_deregister(&mplsip_handler, AF_MPLS)) 6961b69e7e6SSimon Horman pr_info("%s: can't deregister tunnel\n", __func__); 6971b69e7e6SSimon Horman #endif 69886de8a63SEric W. Biederman unregister_pernet_device(&ipip_net_ops); 6991da177e4SLinus Torvalds } 7001da177e4SLinus Torvalds 7011da177e4SLinus Torvalds module_init(ipip_init); 7021da177e4SLinus Torvalds module_exit(ipip_fini); 7031da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 704f98f89a0STom Gundersen MODULE_ALIAS_RTNL_LINK("ipip"); 7058909c9adSVasiliy Kulikov MODULE_ALIAS_NETDEV("tunl0"); 706