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 { 131071f92d0SRami Rosen /* All the routers (except for Linux) return only 132*f3594f0aSXin Long * 8 bytes of packet payload. It means, that precise relaying of 133*f3594f0aSXin Long * ICMP in the real Internet is absolutely infeasible. 1341da177e4SLinus Torvalds */ 135fd58156eSPravin B Shelar struct net *net = dev_net(skb->dev); 136fd58156eSPravin B Shelar struct ip_tunnel_net *itn = net_generic(net, ipip_net_id); 137b71d1d42SEric Dumazet const struct iphdr *iph = (const struct iphdr *)skb->data; 138fd58156eSPravin B Shelar const int type = icmp_hdr(skb)->type; 139fd58156eSPravin B Shelar const int code = icmp_hdr(skb)->code; 140*f3594f0aSXin Long struct ip_tunnel *t; 141*f3594f0aSXin Long int err = 0; 1421da177e4SLinus Torvalds 143*f3594f0aSXin Long switch (type) { 144*f3594f0aSXin Long case ICMP_DEST_UNREACH: 145*f3594f0aSXin Long switch (code) { 146*f3594f0aSXin Long case ICMP_SR_FAILED: 147*f3594f0aSXin Long /* Impossible event. */ 148*f3594f0aSXin Long goto out; 149*f3594f0aSXin Long default: 150*f3594f0aSXin Long /* All others are translated to HOST_UNREACH. 151*f3594f0aSXin Long * rfc2003 contains "deep thoughts" about NET_UNREACH, 152*f3594f0aSXin Long * I believe they are just ether pollution. --ANK 153*f3594f0aSXin Long */ 154*f3594f0aSXin Long break; 155*f3594f0aSXin Long } 156*f3594f0aSXin Long break; 157*f3594f0aSXin Long 158*f3594f0aSXin Long case ICMP_TIME_EXCEEDED: 159*f3594f0aSXin Long if (code != ICMP_EXC_TTL) 160*f3594f0aSXin Long goto out; 161*f3594f0aSXin Long break; 162*f3594f0aSXin Long 163*f3594f0aSXin Long case ICMP_REDIRECT: 164*f3594f0aSXin Long break; 165*f3594f0aSXin Long 166*f3594f0aSXin Long default: 167*f3594f0aSXin Long goto out; 168*f3594f0aSXin Long } 169*f3594f0aSXin Long 170fd58156eSPravin B Shelar t = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY, 171fd58156eSPravin B Shelar iph->daddr, iph->saddr, 0); 172*f3594f0aSXin Long if (!t) { 173*f3594f0aSXin Long err = -ENOENT; 17436393395SDavid S. Miller goto out; 175*f3594f0aSXin Long } 17636393395SDavid S. Miller 17736393395SDavid S. Miller if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) { 178*f3594f0aSXin Long ipv4_update_pmtu(skb, net, info, t->parms.link, 0, 179*f3594f0aSXin Long iph->protocol, 0); 18036393395SDavid S. Miller goto out; 18136393395SDavid S. Miller } 18236393395SDavid S. Miller 18355be7a9cSDavid S. Miller if (type == ICMP_REDIRECT) { 184*f3594f0aSXin Long ipv4_redirect(skb, net, t->parms.link, 0, iph->protocol, 0); 18555be7a9cSDavid S. Miller goto out; 18655be7a9cSDavid S. Miller } 18755be7a9cSDavid S. Miller 188*f3594f0aSXin Long if (t->parms.iph.daddr == 0) { 189*f3594f0aSXin Long err = -ENOENT; 1901da177e4SLinus Torvalds goto out; 191*f3594f0aSXin Long } 192d2acc347SHerbert Xu 1931da177e4SLinus Torvalds if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED) 1941da177e4SLinus Torvalds goto out; 1951da177e4SLinus Torvalds 19626d94b46SWei Yongjun if (time_before(jiffies, t->err_time + IPTUNNEL_ERR_TIMEO)) 1971da177e4SLinus Torvalds t->err_count++; 1981da177e4SLinus Torvalds else 1991da177e4SLinus Torvalds t->err_count = 1; 2001da177e4SLinus Torvalds t->err_time = jiffies; 201b0558ef2Sstephen hemminger 202fd58156eSPravin B Shelar out: 203d2acc347SHerbert Xu return err; 2041da177e4SLinus Torvalds } 2051da177e4SLinus Torvalds 2061b69e7e6SSimon Horman static const struct tnl_ptk_info ipip_tpi = { 207fd58156eSPravin B Shelar /* no tunnel info required for ipip. */ 208fd58156eSPravin B Shelar .proto = htons(ETH_P_IP), 209fd58156eSPravin B Shelar }; 210fd58156eSPravin B Shelar 2111b69e7e6SSimon Horman #if IS_ENABLED(CONFIG_MPLS) 2121b69e7e6SSimon Horman static const struct tnl_ptk_info mplsip_tpi = { 2131b69e7e6SSimon Horman /* no tunnel info required for mplsip. */ 2141b69e7e6SSimon Horman .proto = htons(ETH_P_MPLS_UC), 2151b69e7e6SSimon Horman }; 2161b69e7e6SSimon Horman #endif 2171b69e7e6SSimon Horman 2181b69e7e6SSimon Horman static int ipip_tunnel_rcv(struct sk_buff *skb, u8 ipproto) 2191da177e4SLinus Torvalds { 220fd58156eSPravin B Shelar struct net *net = dev_net(skb->dev); 221fd58156eSPravin B Shelar struct ip_tunnel_net *itn = net_generic(net, ipip_net_id); 222cfc7381bSAlexei Starovoitov struct metadata_dst *tun_dst = NULL; 2231da177e4SLinus Torvalds struct ip_tunnel *tunnel; 2243d7b46cdSPravin B Shelar const struct iphdr *iph; 2251da177e4SLinus Torvalds 2263d7b46cdSPravin B Shelar iph = ip_hdr(skb); 227fd58156eSPravin B Shelar tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY, 228fd58156eSPravin B Shelar iph->saddr, 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) { 247cfc7381bSAlexei Starovoitov tun_dst = ip_tun_rx_dst(skb, 0, 0, 0); 248cfc7381bSAlexei Starovoitov if (!tun_dst) 249cfc7381bSAlexei Starovoitov return 0; 250cfc7381bSAlexei Starovoitov } 251cfc7381bSAlexei Starovoitov return ip_tunnel_rcv(tunnel, skb, tpi, tun_dst, log_ecn_error); 2521da177e4SLinus Torvalds } 2531da177e4SLinus Torvalds 2541da177e4SLinus Torvalds return -1; 255eccc1bb8Sstephen hemminger 256eccc1bb8Sstephen hemminger drop: 257eccc1bb8Sstephen hemminger kfree_skb(skb); 258eccc1bb8Sstephen hemminger return 0; 2591da177e4SLinus Torvalds } 2601da177e4SLinus Torvalds 2611b69e7e6SSimon Horman static int ipip_rcv(struct sk_buff *skb) 2621b69e7e6SSimon Horman { 2631b69e7e6SSimon Horman return ipip_tunnel_rcv(skb, IPPROTO_IPIP); 2641b69e7e6SSimon Horman } 2651b69e7e6SSimon Horman 2661b69e7e6SSimon Horman #if IS_ENABLED(CONFIG_MPLS) 2671b69e7e6SSimon Horman static int mplsip_rcv(struct sk_buff *skb) 2681b69e7e6SSimon Horman { 2691b69e7e6SSimon Horman return ipip_tunnel_rcv(skb, IPPROTO_MPLS); 2701b69e7e6SSimon Horman } 2711b69e7e6SSimon Horman #endif 2721b69e7e6SSimon Horman 2731da177e4SLinus Torvalds /* 2741da177e4SLinus Torvalds * This function assumes it is being called from dev_queue_xmit() 2751da177e4SLinus Torvalds * and that skb is filled properly by that function. 2761da177e4SLinus Torvalds */ 2771b69e7e6SSimon Horman static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, 2781b69e7e6SSimon Horman struct net_device *dev) 2791da177e4SLinus Torvalds { 2802941a486SPatrick McHardy struct ip_tunnel *tunnel = netdev_priv(dev); 281b71d1d42SEric Dumazet const struct iphdr *tiph = &tunnel->parms.iph; 2821b69e7e6SSimon Horman u8 ipproto; 2831da177e4SLinus Torvalds 2841b69e7e6SSimon Horman switch (skb->protocol) { 2851b69e7e6SSimon Horman case htons(ETH_P_IP): 2861b69e7e6SSimon Horman ipproto = IPPROTO_IPIP; 2871b69e7e6SSimon Horman break; 2881b69e7e6SSimon Horman #if IS_ENABLED(CONFIG_MPLS) 2891b69e7e6SSimon Horman case htons(ETH_P_MPLS_UC): 2901b69e7e6SSimon Horman ipproto = IPPROTO_MPLS; 2911b69e7e6SSimon Horman break; 2921b69e7e6SSimon Horman #endif 2931b69e7e6SSimon Horman default: 2941b69e7e6SSimon Horman goto tx_error; 2951b69e7e6SSimon Horman } 2961b69e7e6SSimon Horman 2971b69e7e6SSimon Horman if (tiph->protocol != ipproto && tiph->protocol != 0) 2981da177e4SLinus Torvalds goto tx_error; 299cef401deSEric Dumazet 3007e13318dSTom Herbert if (iptunnel_handle_offloads(skb, SKB_GSO_IPXIP4)) 301aed069dfSAlexander Duyck goto tx_error; 3024f3ed920SPravin B Shelar 3031b69e7e6SSimon Horman skb_set_inner_ipproto(skb, ipproto); 304077c5a09STom Herbert 305cfc7381bSAlexei Starovoitov if (tunnel->collect_md) 306cfc7381bSAlexei Starovoitov ip_md_tunnel_xmit(skb, dev, ipproto); 307cfc7381bSAlexei Starovoitov else 3081b69e7e6SSimon Horman ip_tunnel_xmit(skb, dev, tiph, ipproto); 3096ed10654SPatrick McHardy return NETDEV_TX_OK; 3101da177e4SLinus Torvalds 3111da177e4SLinus Torvalds tx_error: 3123acfa1e7SEric Dumazet kfree_skb(skb); 313aed069dfSAlexander Duyck 314cb32f511SEric Dumazet dev->stats.tx_errors++; 3156ed10654SPatrick McHardy return NETDEV_TX_OK; 3161da177e4SLinus Torvalds } 3171da177e4SLinus Torvalds 3181b69e7e6SSimon Horman static bool ipip_tunnel_ioctl_verify_protocol(u8 ipproto) 3191b69e7e6SSimon Horman { 3201b69e7e6SSimon Horman switch (ipproto) { 3211b69e7e6SSimon Horman case 0: 3221b69e7e6SSimon Horman case IPPROTO_IPIP: 3231b69e7e6SSimon Horman #if IS_ENABLED(CONFIG_MPLS) 3241b69e7e6SSimon Horman case IPPROTO_MPLS: 3251b69e7e6SSimon Horman #endif 3261b69e7e6SSimon Horman return true; 3271b69e7e6SSimon Horman } 3281b69e7e6SSimon Horman 3291b69e7e6SSimon Horman return false; 3301b69e7e6SSimon Horman } 3311b69e7e6SSimon Horman 3321da177e4SLinus Torvalds static int 3331da177e4SLinus Torvalds ipip_tunnel_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) 3341da177e4SLinus Torvalds { 3351da177e4SLinus Torvalds int err = 0; 3361da177e4SLinus Torvalds struct ip_tunnel_parm p; 3371da177e4SLinus Torvalds 3381da177e4SLinus Torvalds if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) 339fd58156eSPravin B Shelar return -EFAULT; 3401da177e4SLinus Torvalds 3413b7b514fSCong Wang if (cmd == SIOCADDTUNNEL || cmd == SIOCCHGTUNNEL) { 3421b69e7e6SSimon Horman if (p.iph.version != 4 || 3431b69e7e6SSimon Horman !ipip_tunnel_ioctl_verify_protocol(p.iph.protocol) || 3441da177e4SLinus Torvalds p.iph.ihl != 5 || (p.iph.frag_off&htons(~IP_DF))) 345fd58156eSPravin B Shelar return -EINVAL; 3463b7b514fSCong Wang } 3473b7b514fSCong Wang 348252a8fbeSEric Dumazet p.i_key = p.o_key = 0; 349252a8fbeSEric Dumazet p.i_flags = p.o_flags = 0; 350fd58156eSPravin B Shelar err = ip_tunnel_ioctl(dev, &p, cmd); 351fd58156eSPravin B Shelar if (err) 3521da177e4SLinus Torvalds return err; 3531da177e4SLinus Torvalds 354fd58156eSPravin B Shelar if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p))) 355fd58156eSPravin B Shelar return -EFAULT; 356fd58156eSPravin B Shelar 3571da177e4SLinus Torvalds return 0; 3581da177e4SLinus Torvalds } 3591da177e4SLinus Torvalds 36023a12b14SStephen Hemminger static const struct net_device_ops ipip_netdev_ops = { 361fd58156eSPravin B Shelar .ndo_init = ipip_tunnel_init, 362fd58156eSPravin B Shelar .ndo_uninit = ip_tunnel_uninit, 36323a12b14SStephen Hemminger .ndo_start_xmit = ipip_tunnel_xmit, 36423a12b14SStephen Hemminger .ndo_do_ioctl = ipip_tunnel_ioctl, 365fd58156eSPravin B Shelar .ndo_change_mtu = ip_tunnel_change_mtu, 366fd58156eSPravin B Shelar .ndo_get_stats64 = ip_tunnel_get_stats64, 3671e99584bSNicolas Dichtel .ndo_get_iflink = ip_tunnel_get_iflink, 36823a12b14SStephen Hemminger }; 36923a12b14SStephen Hemminger 370c3b89fbbSEric Dumazet #define IPIP_FEATURES (NETIF_F_SG | \ 371c3b89fbbSEric Dumazet NETIF_F_FRAGLIST | \ 372c3b89fbbSEric Dumazet NETIF_F_HIGHDMA | \ 373cb32f511SEric Dumazet NETIF_F_GSO_SOFTWARE | \ 374c3b89fbbSEric Dumazet NETIF_F_HW_CSUM) 375c3b89fbbSEric Dumazet 3761da177e4SLinus Torvalds static void ipip_tunnel_setup(struct net_device *dev) 3771da177e4SLinus Torvalds { 37823a12b14SStephen Hemminger dev->netdev_ops = &ipip_netdev_ops; 3791da177e4SLinus Torvalds 3801da177e4SLinus Torvalds dev->type = ARPHRD_TUNNEL; 3811da177e4SLinus Torvalds dev->flags = IFF_NOARP; 3821da177e4SLinus Torvalds dev->addr_len = 4; 383153f0943SEric Dumazet dev->features |= NETIF_F_LLTX; 38402875878SEric Dumazet netif_keep_dst(dev); 385c3b89fbbSEric Dumazet 386c3b89fbbSEric Dumazet dev->features |= IPIP_FEATURES; 387c3b89fbbSEric Dumazet dev->hw_features |= IPIP_FEATURES; 388fd58156eSPravin B Shelar ip_tunnel_setup(dev, ipip_net_id); 3891da177e4SLinus Torvalds } 3901da177e4SLinus Torvalds 3913c97af99SEric Dumazet static int ipip_tunnel_init(struct net_device *dev) 3921da177e4SLinus Torvalds { 39323a12b14SStephen Hemminger struct ip_tunnel *tunnel = netdev_priv(dev); 3941da177e4SLinus Torvalds 3951da177e4SLinus Torvalds memcpy(dev->dev_addr, &tunnel->parms.iph.saddr, 4); 3961da177e4SLinus Torvalds memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4); 3971da177e4SLinus Torvalds 398473ab820STom Herbert tunnel->tun_hlen = 0; 399473ab820STom Herbert tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen; 400fd58156eSPravin B Shelar return ip_tunnel_init(dev); 4011da177e4SLinus Torvalds } 4021da177e4SLinus Torvalds 403a8b8a889SMatthias Schiffer static int ipip_tunnel_validate(struct nlattr *tb[], struct nlattr *data[], 404a8b8a889SMatthias Schiffer struct netlink_ext_ack *extack) 4051b69e7e6SSimon Horman { 4061b69e7e6SSimon Horman u8 proto; 4071b69e7e6SSimon Horman 4081b69e7e6SSimon Horman if (!data || !data[IFLA_IPTUN_PROTO]) 4091b69e7e6SSimon Horman return 0; 4101b69e7e6SSimon Horman 4111b69e7e6SSimon Horman proto = nla_get_u8(data[IFLA_IPTUN_PROTO]); 4121b69e7e6SSimon Horman if (proto != IPPROTO_IPIP && proto != IPPROTO_MPLS && proto != 0) 4131b69e7e6SSimon Horman return -EINVAL; 4141b69e7e6SSimon Horman 4151b69e7e6SSimon Horman return 0; 4161b69e7e6SSimon Horman } 4171b69e7e6SSimon Horman 418be42da0eSNicolas Dichtel static void ipip_netlink_parms(struct nlattr *data[], 4199830ad4cSCraig Gallek struct ip_tunnel_parm *parms, bool *collect_md, 4209830ad4cSCraig Gallek __u32 *fwmark) 421be42da0eSNicolas Dichtel { 422be42da0eSNicolas Dichtel memset(parms, 0, sizeof(*parms)); 423be42da0eSNicolas Dichtel 424be42da0eSNicolas Dichtel parms->iph.version = 4; 425be42da0eSNicolas Dichtel parms->iph.protocol = IPPROTO_IPIP; 426be42da0eSNicolas Dichtel parms->iph.ihl = 5; 427cfc7381bSAlexei Starovoitov *collect_md = false; 428be42da0eSNicolas Dichtel 429be42da0eSNicolas Dichtel if (!data) 430be42da0eSNicolas Dichtel return; 431be42da0eSNicolas Dichtel 432be42da0eSNicolas Dichtel if (data[IFLA_IPTUN_LINK]) 433be42da0eSNicolas Dichtel parms->link = nla_get_u32(data[IFLA_IPTUN_LINK]); 434be42da0eSNicolas Dichtel 435be42da0eSNicolas Dichtel if (data[IFLA_IPTUN_LOCAL]) 43667b61f6cSJiri Benc parms->iph.saddr = nla_get_in_addr(data[IFLA_IPTUN_LOCAL]); 437be42da0eSNicolas Dichtel 438be42da0eSNicolas Dichtel if (data[IFLA_IPTUN_REMOTE]) 43967b61f6cSJiri Benc parms->iph.daddr = nla_get_in_addr(data[IFLA_IPTUN_REMOTE]); 440be42da0eSNicolas Dichtel 441be42da0eSNicolas Dichtel if (data[IFLA_IPTUN_TTL]) { 442be42da0eSNicolas Dichtel parms->iph.ttl = nla_get_u8(data[IFLA_IPTUN_TTL]); 443be42da0eSNicolas Dichtel if (parms->iph.ttl) 444be42da0eSNicolas Dichtel parms->iph.frag_off = htons(IP_DF); 445be42da0eSNicolas Dichtel } 446be42da0eSNicolas Dichtel 447be42da0eSNicolas Dichtel if (data[IFLA_IPTUN_TOS]) 448be42da0eSNicolas Dichtel parms->iph.tos = nla_get_u8(data[IFLA_IPTUN_TOS]); 449be42da0eSNicolas Dichtel 4501b69e7e6SSimon Horman if (data[IFLA_IPTUN_PROTO]) 4511b69e7e6SSimon Horman parms->iph.protocol = nla_get_u8(data[IFLA_IPTUN_PROTO]); 4521b69e7e6SSimon Horman 453be42da0eSNicolas Dichtel if (!data[IFLA_IPTUN_PMTUDISC] || nla_get_u8(data[IFLA_IPTUN_PMTUDISC])) 454be42da0eSNicolas Dichtel parms->iph.frag_off = htons(IP_DF); 455cfc7381bSAlexei Starovoitov 456cfc7381bSAlexei Starovoitov if (data[IFLA_IPTUN_COLLECT_METADATA]) 457cfc7381bSAlexei Starovoitov *collect_md = true; 4589830ad4cSCraig Gallek 4599830ad4cSCraig Gallek if (data[IFLA_IPTUN_FWMARK]) 4609830ad4cSCraig Gallek *fwmark = nla_get_u32(data[IFLA_IPTUN_FWMARK]); 461be42da0eSNicolas Dichtel } 462be42da0eSNicolas Dichtel 463473ab820STom Herbert /* This function returns true when ENCAP attributes are present in the nl msg */ 464473ab820STom Herbert static bool ipip_netlink_encap_parms(struct nlattr *data[], 465473ab820STom Herbert struct ip_tunnel_encap *ipencap) 466473ab820STom Herbert { 467473ab820STom Herbert bool ret = false; 468473ab820STom Herbert 469473ab820STom Herbert memset(ipencap, 0, sizeof(*ipencap)); 470473ab820STom Herbert 471473ab820STom Herbert if (!data) 472473ab820STom Herbert return ret; 473473ab820STom Herbert 474473ab820STom Herbert if (data[IFLA_IPTUN_ENCAP_TYPE]) { 475473ab820STom Herbert ret = true; 476473ab820STom Herbert ipencap->type = nla_get_u16(data[IFLA_IPTUN_ENCAP_TYPE]); 477473ab820STom Herbert } 478473ab820STom Herbert 479473ab820STom Herbert if (data[IFLA_IPTUN_ENCAP_FLAGS]) { 480473ab820STom Herbert ret = true; 481473ab820STom Herbert ipencap->flags = nla_get_u16(data[IFLA_IPTUN_ENCAP_FLAGS]); 482473ab820STom Herbert } 483473ab820STom Herbert 484473ab820STom Herbert if (data[IFLA_IPTUN_ENCAP_SPORT]) { 485473ab820STom Herbert ret = true; 4863e97fa70SSabrina Dubroca ipencap->sport = nla_get_be16(data[IFLA_IPTUN_ENCAP_SPORT]); 487473ab820STom Herbert } 488473ab820STom Herbert 489473ab820STom Herbert if (data[IFLA_IPTUN_ENCAP_DPORT]) { 490473ab820STom Herbert ret = true; 4913e97fa70SSabrina Dubroca ipencap->dport = nla_get_be16(data[IFLA_IPTUN_ENCAP_DPORT]); 492473ab820STom Herbert } 493473ab820STom Herbert 494473ab820STom Herbert return ret; 495473ab820STom Herbert } 496473ab820STom Herbert 497be42da0eSNicolas Dichtel static int ipip_newlink(struct net *src_net, struct net_device *dev, 4987a3f4a18SMatthias Schiffer struct nlattr *tb[], struct nlattr *data[], 4997a3f4a18SMatthias Schiffer struct netlink_ext_ack *extack) 500be42da0eSNicolas Dichtel { 501cfc7381bSAlexei Starovoitov struct ip_tunnel *t = netdev_priv(dev); 502fd58156eSPravin B Shelar struct ip_tunnel_parm p; 503473ab820STom Herbert struct ip_tunnel_encap ipencap; 5049830ad4cSCraig Gallek __u32 fwmark = 0; 505473ab820STom Herbert 506473ab820STom Herbert if (ipip_netlink_encap_parms(data, &ipencap)) { 507473ab820STom Herbert int err = ip_tunnel_encap_setup(t, &ipencap); 508473ab820STom Herbert 509473ab820STom Herbert if (err < 0) 510473ab820STom Herbert return err; 511473ab820STom Herbert } 512be42da0eSNicolas Dichtel 5139830ad4cSCraig Gallek ipip_netlink_parms(data, &p, &t->collect_md, &fwmark); 5149830ad4cSCraig Gallek return ip_tunnel_newlink(dev, tb, &p, fwmark); 515be42da0eSNicolas Dichtel } 516be42da0eSNicolas Dichtel 517be42da0eSNicolas Dichtel static int ipip_changelink(struct net_device *dev, struct nlattr *tb[], 518ad744b22SMatthias Schiffer struct nlattr *data[], 519ad744b22SMatthias Schiffer struct netlink_ext_ack *extack) 520be42da0eSNicolas Dichtel { 5219830ad4cSCraig Gallek struct ip_tunnel *t = netdev_priv(dev); 522be42da0eSNicolas Dichtel struct ip_tunnel_parm p; 523473ab820STom Herbert struct ip_tunnel_encap ipencap; 524cfc7381bSAlexei Starovoitov bool collect_md; 5259830ad4cSCraig Gallek __u32 fwmark = t->fwmark; 526473ab820STom Herbert 527473ab820STom Herbert if (ipip_netlink_encap_parms(data, &ipencap)) { 528473ab820STom Herbert int err = ip_tunnel_encap_setup(t, &ipencap); 529473ab820STom Herbert 530473ab820STom Herbert if (err < 0) 531473ab820STom Herbert return err; 532473ab820STom Herbert } 533be42da0eSNicolas Dichtel 5349830ad4cSCraig Gallek ipip_netlink_parms(data, &p, &collect_md, &fwmark); 535cfc7381bSAlexei Starovoitov if (collect_md) 536cfc7381bSAlexei Starovoitov return -EINVAL; 537be42da0eSNicolas Dichtel 538be42da0eSNicolas Dichtel if (((dev->flags & IFF_POINTOPOINT) && !p.iph.daddr) || 539be42da0eSNicolas Dichtel (!(dev->flags & IFF_POINTOPOINT) && p.iph.daddr)) 540be42da0eSNicolas Dichtel return -EINVAL; 541be42da0eSNicolas Dichtel 5429830ad4cSCraig Gallek return ip_tunnel_changelink(dev, tb, &p, fwmark); 543be42da0eSNicolas Dichtel } 544be42da0eSNicolas Dichtel 5450974658dSNicolas Dichtel static size_t ipip_get_size(const struct net_device *dev) 5460974658dSNicolas Dichtel { 5470974658dSNicolas Dichtel return 5480974658dSNicolas Dichtel /* IFLA_IPTUN_LINK */ 5490974658dSNicolas Dichtel nla_total_size(4) + 5500974658dSNicolas Dichtel /* IFLA_IPTUN_LOCAL */ 5510974658dSNicolas Dichtel nla_total_size(4) + 5520974658dSNicolas Dichtel /* IFLA_IPTUN_REMOTE */ 5530974658dSNicolas Dichtel nla_total_size(4) + 5540974658dSNicolas Dichtel /* IFLA_IPTUN_TTL */ 5550974658dSNicolas Dichtel nla_total_size(1) + 5560974658dSNicolas Dichtel /* IFLA_IPTUN_TOS */ 5570974658dSNicolas Dichtel nla_total_size(1) + 5581b69e7e6SSimon Horman /* IFLA_IPTUN_PROTO */ 5591b69e7e6SSimon Horman nla_total_size(1) + 560befe2aa1SNicolas Dichtel /* IFLA_IPTUN_PMTUDISC */ 561befe2aa1SNicolas Dichtel nla_total_size(1) + 562473ab820STom Herbert /* IFLA_IPTUN_ENCAP_TYPE */ 563473ab820STom Herbert nla_total_size(2) + 564473ab820STom Herbert /* IFLA_IPTUN_ENCAP_FLAGS */ 565473ab820STom Herbert nla_total_size(2) + 566473ab820STom Herbert /* IFLA_IPTUN_ENCAP_SPORT */ 567473ab820STom Herbert nla_total_size(2) + 568473ab820STom Herbert /* IFLA_IPTUN_ENCAP_DPORT */ 569473ab820STom Herbert nla_total_size(2) + 570cfc7381bSAlexei Starovoitov /* IFLA_IPTUN_COLLECT_METADATA */ 571cfc7381bSAlexei Starovoitov nla_total_size(0) + 5729830ad4cSCraig Gallek /* IFLA_IPTUN_FWMARK */ 5739830ad4cSCraig Gallek nla_total_size(4) + 5740974658dSNicolas Dichtel 0; 5750974658dSNicolas Dichtel } 5760974658dSNicolas Dichtel 5770974658dSNicolas Dichtel static int ipip_fill_info(struct sk_buff *skb, const struct net_device *dev) 5780974658dSNicolas Dichtel { 5790974658dSNicolas Dichtel struct ip_tunnel *tunnel = netdev_priv(dev); 5800974658dSNicolas Dichtel struct ip_tunnel_parm *parm = &tunnel->parms; 5810974658dSNicolas Dichtel 5820974658dSNicolas Dichtel if (nla_put_u32(skb, IFLA_IPTUN_LINK, parm->link) || 583930345eaSJiri Benc nla_put_in_addr(skb, IFLA_IPTUN_LOCAL, parm->iph.saddr) || 584930345eaSJiri Benc nla_put_in_addr(skb, IFLA_IPTUN_REMOTE, parm->iph.daddr) || 5850974658dSNicolas Dichtel nla_put_u8(skb, IFLA_IPTUN_TTL, parm->iph.ttl) || 586befe2aa1SNicolas Dichtel nla_put_u8(skb, IFLA_IPTUN_TOS, parm->iph.tos) || 5871b69e7e6SSimon Horman nla_put_u8(skb, IFLA_IPTUN_PROTO, parm->iph.protocol) || 588befe2aa1SNicolas Dichtel nla_put_u8(skb, IFLA_IPTUN_PMTUDISC, 5899830ad4cSCraig Gallek !!(parm->iph.frag_off & htons(IP_DF))) || 5909830ad4cSCraig Gallek nla_put_u32(skb, IFLA_IPTUN_FWMARK, tunnel->fwmark)) 5910974658dSNicolas Dichtel goto nla_put_failure; 592473ab820STom Herbert 593473ab820STom Herbert if (nla_put_u16(skb, IFLA_IPTUN_ENCAP_TYPE, 594473ab820STom Herbert tunnel->encap.type) || 5953e97fa70SSabrina Dubroca nla_put_be16(skb, IFLA_IPTUN_ENCAP_SPORT, 596473ab820STom Herbert tunnel->encap.sport) || 5973e97fa70SSabrina Dubroca nla_put_be16(skb, IFLA_IPTUN_ENCAP_DPORT, 598473ab820STom Herbert tunnel->encap.dport) || 599473ab820STom Herbert nla_put_u16(skb, IFLA_IPTUN_ENCAP_FLAGS, 600e1b2cb65STom Herbert tunnel->encap.flags)) 601473ab820STom Herbert goto nla_put_failure; 602473ab820STom Herbert 603cfc7381bSAlexei Starovoitov if (tunnel->collect_md) 604cfc7381bSAlexei Starovoitov if (nla_put_flag(skb, IFLA_IPTUN_COLLECT_METADATA)) 605cfc7381bSAlexei Starovoitov goto nla_put_failure; 6060974658dSNicolas Dichtel return 0; 6070974658dSNicolas Dichtel 6080974658dSNicolas Dichtel nla_put_failure: 6090974658dSNicolas Dichtel return -EMSGSIZE; 6100974658dSNicolas Dichtel } 6110974658dSNicolas Dichtel 612be42da0eSNicolas Dichtel static const struct nla_policy ipip_policy[IFLA_IPTUN_MAX + 1] = { 613be42da0eSNicolas Dichtel [IFLA_IPTUN_LINK] = { .type = NLA_U32 }, 614be42da0eSNicolas Dichtel [IFLA_IPTUN_LOCAL] = { .type = NLA_U32 }, 615be42da0eSNicolas Dichtel [IFLA_IPTUN_REMOTE] = { .type = NLA_U32 }, 616be42da0eSNicolas Dichtel [IFLA_IPTUN_TTL] = { .type = NLA_U8 }, 617be42da0eSNicolas Dichtel [IFLA_IPTUN_TOS] = { .type = NLA_U8 }, 6181b69e7e6SSimon Horman [IFLA_IPTUN_PROTO] = { .type = NLA_U8 }, 619be42da0eSNicolas Dichtel [IFLA_IPTUN_PMTUDISC] = { .type = NLA_U8 }, 620473ab820STom Herbert [IFLA_IPTUN_ENCAP_TYPE] = { .type = NLA_U16 }, 621473ab820STom Herbert [IFLA_IPTUN_ENCAP_FLAGS] = { .type = NLA_U16 }, 622473ab820STom Herbert [IFLA_IPTUN_ENCAP_SPORT] = { .type = NLA_U16 }, 623473ab820STom Herbert [IFLA_IPTUN_ENCAP_DPORT] = { .type = NLA_U16 }, 624cfc7381bSAlexei Starovoitov [IFLA_IPTUN_COLLECT_METADATA] = { .type = NLA_FLAG }, 6259830ad4cSCraig Gallek [IFLA_IPTUN_FWMARK] = { .type = NLA_U32 }, 626be42da0eSNicolas Dichtel }; 627be42da0eSNicolas Dichtel 6280974658dSNicolas Dichtel static struct rtnl_link_ops ipip_link_ops __read_mostly = { 6290974658dSNicolas Dichtel .kind = "ipip", 6300974658dSNicolas Dichtel .maxtype = IFLA_IPTUN_MAX, 631be42da0eSNicolas Dichtel .policy = ipip_policy, 6320974658dSNicolas Dichtel .priv_size = sizeof(struct ip_tunnel), 633be42da0eSNicolas Dichtel .setup = ipip_tunnel_setup, 6341b69e7e6SSimon Horman .validate = ipip_tunnel_validate, 635be42da0eSNicolas Dichtel .newlink = ipip_newlink, 636be42da0eSNicolas Dichtel .changelink = ipip_changelink, 637fd58156eSPravin B Shelar .dellink = ip_tunnel_dellink, 6380974658dSNicolas Dichtel .get_size = ipip_get_size, 6390974658dSNicolas Dichtel .fill_info = ipip_fill_info, 6401728d4faSNicolas Dichtel .get_link_net = ip_tunnel_get_link_net, 6410974658dSNicolas Dichtel }; 6420974658dSNicolas Dichtel 6436dcd814bSEric Dumazet static struct xfrm_tunnel ipip_handler __read_mostly = { 6441da177e4SLinus Torvalds .handler = ipip_rcv, 6451da177e4SLinus Torvalds .err_handler = ipip_err, 646d2acc347SHerbert Xu .priority = 1, 6471da177e4SLinus Torvalds }; 6481da177e4SLinus Torvalds 6491b69e7e6SSimon Horman #if IS_ENABLED(CONFIG_MPLS) 6501b69e7e6SSimon Horman static struct xfrm_tunnel mplsip_handler __read_mostly = { 6511b69e7e6SSimon Horman .handler = mplsip_rcv, 6521b69e7e6SSimon Horman .err_handler = ipip_err, 6531b69e7e6SSimon Horman .priority = 1, 6541b69e7e6SSimon Horman }; 6551b69e7e6SSimon Horman #endif 6561b69e7e6SSimon Horman 6572c8c1e72SAlexey Dobriyan static int __net_init ipip_init_net(struct net *net) 65810dc4c7bSPavel Emelyanov { 659fd58156eSPravin B Shelar return ip_tunnel_init_net(net, ipip_net_id, &ipip_link_ops, "tunl0"); 66010dc4c7bSPavel Emelyanov } 66110dc4c7bSPavel Emelyanov 6622c8c1e72SAlexey Dobriyan static void __net_exit ipip_exit_net(struct net *net) 66310dc4c7bSPavel Emelyanov { 664fd58156eSPravin B Shelar struct ip_tunnel_net *itn = net_generic(net, ipip_net_id); 6656c742e71SNicolas Dichtel ip_tunnel_delete_net(itn, &ipip_link_ops); 66610dc4c7bSPavel Emelyanov } 66710dc4c7bSPavel Emelyanov 66810dc4c7bSPavel Emelyanov static struct pernet_operations ipip_net_ops = { 66910dc4c7bSPavel Emelyanov .init = ipip_init_net, 67010dc4c7bSPavel Emelyanov .exit = ipip_exit_net, 67186de8a63SEric W. Biederman .id = &ipip_net_id, 672fd58156eSPravin B Shelar .size = sizeof(struct ip_tunnel_net), 67310dc4c7bSPavel Emelyanov }; 67410dc4c7bSPavel Emelyanov 6751da177e4SLinus Torvalds static int __init ipip_init(void) 6761da177e4SLinus Torvalds { 6771da177e4SLinus Torvalds int err; 6781da177e4SLinus Torvalds 6791b69e7e6SSimon Horman pr_info("ipip: IPv4 and MPLS over IPv4 tunneling driver\n"); 6801da177e4SLinus Torvalds 68186de8a63SEric W. Biederman err = register_pernet_device(&ipip_net_ops); 682d5aa407fSAlexey Dobriyan if (err < 0) 683d5aa407fSAlexey Dobriyan return err; 684d5aa407fSAlexey Dobriyan err = xfrm4_tunnel_register(&ipip_handler, AF_INET); 685d5aa407fSAlexey Dobriyan if (err < 0) { 686058bd4d2SJoe Perches pr_info("%s: can't register tunnel\n", __func__); 6871b69e7e6SSimon Horman goto xfrm_tunnel_ipip_failed; 688d5aa407fSAlexey Dobriyan } 6891b69e7e6SSimon Horman #if IS_ENABLED(CONFIG_MPLS) 6901b69e7e6SSimon Horman err = xfrm4_tunnel_register(&mplsip_handler, AF_MPLS); 6911b69e7e6SSimon Horman if (err < 0) { 6921b69e7e6SSimon Horman pr_info("%s: can't register tunnel\n", __func__); 6931b69e7e6SSimon Horman goto xfrm_tunnel_mplsip_failed; 6941b69e7e6SSimon Horman } 6951b69e7e6SSimon Horman #endif 6960974658dSNicolas Dichtel err = rtnl_link_register(&ipip_link_ops); 6970974658dSNicolas Dichtel if (err < 0) 6980974658dSNicolas Dichtel goto rtnl_link_failed; 6990974658dSNicolas Dichtel 7000974658dSNicolas Dichtel out: 701b9855c54SPavel Emelyanov return err; 7020974658dSNicolas Dichtel 7030974658dSNicolas Dichtel rtnl_link_failed: 7041b69e7e6SSimon Horman #if IS_ENABLED(CONFIG_MPLS) 7051b69e7e6SSimon Horman xfrm4_tunnel_deregister(&mplsip_handler, AF_INET); 7061b69e7e6SSimon Horman xfrm_tunnel_mplsip_failed: 7071b69e7e6SSimon Horman 7081b69e7e6SSimon Horman #endif 7090974658dSNicolas Dichtel xfrm4_tunnel_deregister(&ipip_handler, AF_INET); 7101b69e7e6SSimon Horman xfrm_tunnel_ipip_failed: 7110974658dSNicolas Dichtel unregister_pernet_device(&ipip_net_ops); 7120974658dSNicolas Dichtel goto out; 7131da177e4SLinus Torvalds } 7141da177e4SLinus Torvalds 7151da177e4SLinus Torvalds static void __exit ipip_fini(void) 7161da177e4SLinus Torvalds { 7170974658dSNicolas Dichtel rtnl_link_unregister(&ipip_link_ops); 718c0d56408SKazunori MIYAZAWA if (xfrm4_tunnel_deregister(&ipip_handler, AF_INET)) 719058bd4d2SJoe Perches pr_info("%s: can't deregister tunnel\n", __func__); 7201b69e7e6SSimon Horman #if IS_ENABLED(CONFIG_MPLS) 7211b69e7e6SSimon Horman if (xfrm4_tunnel_deregister(&mplsip_handler, AF_MPLS)) 7221b69e7e6SSimon Horman pr_info("%s: can't deregister tunnel\n", __func__); 7231b69e7e6SSimon Horman #endif 72486de8a63SEric W. Biederman unregister_pernet_device(&ipip_net_ops); 7251da177e4SLinus Torvalds } 7261da177e4SLinus Torvalds 7271da177e4SLinus Torvalds module_init(ipip_init); 7281da177e4SLinus Torvalds module_exit(ipip_fini); 7291da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 730f98f89a0STom Gundersen MODULE_ALIAS_RTNL_LINK("ipip"); 7318909c9adSVasiliy Kulikov MODULE_ALIAS_NETDEV("tunl0"); 732