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
ipip_err(struct sk_buff * skb,u32 info)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;
133fd58156eSPravin B Shelar const int type = icmp_hdr(skb)->type;
134fd58156eSPravin B Shelar const int code = icmp_hdr(skb)->code;
135f3594f0aSXin Long struct ip_tunnel *t;
136f3594f0aSXin Long int err = 0;
1371da177e4SLinus Torvalds
13832bbd879SStefano Brivio t = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY,
13932bbd879SStefano Brivio iph->daddr, iph->saddr, 0);
14032bbd879SStefano Brivio if (!t) {
14132bbd879SStefano Brivio err = -ENOENT;
14232bbd879SStefano Brivio goto out;
14332bbd879SStefano Brivio }
14432bbd879SStefano Brivio
145f3594f0aSXin Long switch (type) {
146f3594f0aSXin Long case ICMP_DEST_UNREACH:
147f3594f0aSXin Long switch (code) {
148f3594f0aSXin Long case ICMP_SR_FAILED:
149f3594f0aSXin Long /* Impossible event. */
150f3594f0aSXin Long goto out;
151f3594f0aSXin Long default:
152f3594f0aSXin Long /* All others are translated to HOST_UNREACH.
153f3594f0aSXin Long * rfc2003 contains "deep thoughts" about NET_UNREACH,
154f3594f0aSXin Long * I believe they are just ether pollution. --ANK
155f3594f0aSXin Long */
156f3594f0aSXin Long break;
157f3594f0aSXin Long }
158f3594f0aSXin Long break;
159f3594f0aSXin Long
160f3594f0aSXin Long case ICMP_TIME_EXCEEDED:
161f3594f0aSXin Long if (code != ICMP_EXC_TTL)
162f3594f0aSXin Long goto out;
163f3594f0aSXin Long break;
164f3594f0aSXin Long
165f3594f0aSXin Long case ICMP_REDIRECT:
166f3594f0aSXin Long break;
167f3594f0aSXin Long
168f3594f0aSXin Long default:
169f3594f0aSXin Long goto out;
170f3594f0aSXin Long }
171f3594f0aSXin Long
17236393395SDavid S. Miller if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) {
173d888f396SMaciej Żenczykowski ipv4_update_pmtu(skb, net, info, t->parms.link, iph->protocol);
17436393395SDavid S. Miller goto out;
17536393395SDavid S. Miller }
17636393395SDavid S. Miller
17755be7a9cSDavid S. Miller if (type == ICMP_REDIRECT) {
1781042caa7SMaciej Żenczykowski ipv4_redirect(skb, net, t->parms.link, iph->protocol);
17955be7a9cSDavid S. Miller goto out;
18055be7a9cSDavid S. Miller }
18155be7a9cSDavid S. Miller
182f3594f0aSXin Long if (t->parms.iph.daddr == 0) {
183f3594f0aSXin Long err = -ENOENT;
1841da177e4SLinus Torvalds goto out;
185f3594f0aSXin Long }
186d2acc347SHerbert Xu
1871da177e4SLinus Torvalds if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED)
1881da177e4SLinus Torvalds goto out;
1891da177e4SLinus Torvalds
19026d94b46SWei Yongjun if (time_before(jiffies, t->err_time + IPTUNNEL_ERR_TIMEO))
1911da177e4SLinus Torvalds t->err_count++;
1921da177e4SLinus Torvalds else
1931da177e4SLinus Torvalds t->err_count = 1;
1941da177e4SLinus Torvalds t->err_time = jiffies;
195b0558ef2Sstephen hemminger
196fd58156eSPravin B Shelar out:
197d2acc347SHerbert Xu return err;
1981da177e4SLinus Torvalds }
1991da177e4SLinus Torvalds
2001b69e7e6SSimon Horman static const struct tnl_ptk_info ipip_tpi = {
201fd58156eSPravin B Shelar /* no tunnel info required for ipip. */
202fd58156eSPravin B Shelar .proto = htons(ETH_P_IP),
203fd58156eSPravin B Shelar };
204fd58156eSPravin B Shelar
2051b69e7e6SSimon Horman #if IS_ENABLED(CONFIG_MPLS)
2061b69e7e6SSimon Horman static const struct tnl_ptk_info mplsip_tpi = {
2071b69e7e6SSimon Horman /* no tunnel info required for mplsip. */
2081b69e7e6SSimon Horman .proto = htons(ETH_P_MPLS_UC),
2091b69e7e6SSimon Horman };
2101b69e7e6SSimon Horman #endif
2111b69e7e6SSimon Horman
ipip_tunnel_rcv(struct sk_buff * skb,u8 ipproto)2121b69e7e6SSimon Horman static int ipip_tunnel_rcv(struct sk_buff *skb, u8 ipproto)
2131da177e4SLinus Torvalds {
214fd58156eSPravin B Shelar struct net *net = dev_net(skb->dev);
215fd58156eSPravin B Shelar struct ip_tunnel_net *itn = net_generic(net, ipip_net_id);
216cfc7381bSAlexei Starovoitov struct metadata_dst *tun_dst = NULL;
2171da177e4SLinus Torvalds struct ip_tunnel *tunnel;
2183d7b46cdSPravin B Shelar const struct iphdr *iph;
2191da177e4SLinus Torvalds
2203d7b46cdSPravin B Shelar iph = ip_hdr(skb);
221fd58156eSPravin B Shelar tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY,
222fd58156eSPravin B Shelar iph->saddr, iph->daddr, 0);
223fd58156eSPravin B Shelar if (tunnel) {
2241b69e7e6SSimon Horman const struct tnl_ptk_info *tpi;
2251b69e7e6SSimon Horman
2261b69e7e6SSimon Horman if (tunnel->parms.iph.protocol != ipproto &&
2271b69e7e6SSimon Horman tunnel->parms.iph.protocol != 0)
2281b69e7e6SSimon Horman goto drop;
2291b69e7e6SSimon Horman
230eccc1bb8Sstephen hemminger if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb))
231eccc1bb8Sstephen hemminger goto drop;
2321b69e7e6SSimon Horman #if IS_ENABLED(CONFIG_MPLS)
2331b69e7e6SSimon Horman if (ipproto == IPPROTO_MPLS)
2341b69e7e6SSimon Horman tpi = &mplsip_tpi;
2351b69e7e6SSimon Horman else
2361b69e7e6SSimon Horman #endif
2371b69e7e6SSimon Horman tpi = &ipip_tpi;
2381b69e7e6SSimon Horman if (iptunnel_pull_header(skb, 0, tpi->proto, false))
239737e828bSLi Hongjun goto drop;
240cfc7381bSAlexei Starovoitov if (tunnel->collect_md) {
241cfc7381bSAlexei Starovoitov tun_dst = ip_tun_rx_dst(skb, 0, 0, 0);
242cfc7381bSAlexei Starovoitov if (!tun_dst)
243cfc7381bSAlexei Starovoitov return 0;
244*ac931d4cSChristian Ehrig ip_tunnel_md_udp_encap(skb, &tun_dst->u.tun_info);
245cfc7381bSAlexei Starovoitov }
2467ad136fdSGuillaume Nault skb_reset_mac_header(skb);
2477ad136fdSGuillaume Nault
248cfc7381bSAlexei Starovoitov return ip_tunnel_rcv(tunnel, skb, tpi, tun_dst, log_ecn_error);
2491da177e4SLinus Torvalds }
2501da177e4SLinus Torvalds
2511da177e4SLinus Torvalds return -1;
252eccc1bb8Sstephen hemminger
253eccc1bb8Sstephen hemminger drop:
254eccc1bb8Sstephen hemminger kfree_skb(skb);
255eccc1bb8Sstephen hemminger return 0;
2561da177e4SLinus Torvalds }
2571da177e4SLinus Torvalds
ipip_rcv(struct sk_buff * skb)2581b69e7e6SSimon Horman static int ipip_rcv(struct sk_buff *skb)
2591b69e7e6SSimon Horman {
2601b69e7e6SSimon Horman return ipip_tunnel_rcv(skb, IPPROTO_IPIP);
2611b69e7e6SSimon Horman }
2621b69e7e6SSimon Horman
2631b69e7e6SSimon Horman #if IS_ENABLED(CONFIG_MPLS)
mplsip_rcv(struct sk_buff * skb)2641b69e7e6SSimon Horman static int mplsip_rcv(struct sk_buff *skb)
2651b69e7e6SSimon Horman {
2661b69e7e6SSimon Horman return ipip_tunnel_rcv(skb, IPPROTO_MPLS);
2671b69e7e6SSimon Horman }
2681b69e7e6SSimon Horman #endif
2691b69e7e6SSimon Horman
2701da177e4SLinus Torvalds /*
2711da177e4SLinus Torvalds * This function assumes it is being called from dev_queue_xmit()
2721da177e4SLinus Torvalds * and that skb is filled properly by that function.
2731da177e4SLinus Torvalds */
ipip_tunnel_xmit(struct sk_buff * skb,struct net_device * dev)2741b69e7e6SSimon Horman static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb,
2751b69e7e6SSimon Horman struct net_device *dev)
2761da177e4SLinus Torvalds {
2772941a486SPatrick McHardy struct ip_tunnel *tunnel = netdev_priv(dev);
278b71d1d42SEric Dumazet const struct iphdr *tiph = &tunnel->parms.iph;
2791b69e7e6SSimon Horman u8 ipproto;
2801da177e4SLinus Torvalds
28147d858d0SHaishuang Yan if (!pskb_inet_may_pull(skb))
28247d858d0SHaishuang Yan goto tx_error;
28347d858d0SHaishuang Yan
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)
306c8b34e68Swenxu ip_md_tunnel_xmit(skb, dev, ipproto, 0);
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
314c4794d22SEric Dumazet DEV_STATS_INC(dev, tx_errors);
3156ed10654SPatrick McHardy return NETDEV_TX_OK;
3161da177e4SLinus Torvalds }
3171da177e4SLinus Torvalds
ipip_tunnel_ioctl_verify_protocol(u8 ipproto)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
ipip_tunnel_ctl(struct net_device * dev,struct ip_tunnel_parm * p,int cmd)333607259a6SChristoph Hellwig ipip_tunnel_ctl(struct net_device *dev, struct ip_tunnel_parm *p, int cmd)
3341da177e4SLinus Torvalds {
3353b7b514fSCong Wang if (cmd == SIOCADDTUNNEL || cmd == SIOCCHGTUNNEL) {
336607259a6SChristoph Hellwig if (p->iph.version != 4 ||
337607259a6SChristoph Hellwig !ipip_tunnel_ioctl_verify_protocol(p->iph.protocol) ||
338607259a6SChristoph Hellwig p->iph.ihl != 5 || (p->iph.frag_off & htons(~IP_DF)))
339fd58156eSPravin B Shelar return -EINVAL;
3403b7b514fSCong Wang }
3413b7b514fSCong Wang
342607259a6SChristoph Hellwig p->i_key = p->o_key = 0;
343607259a6SChristoph Hellwig p->i_flags = p->o_flags = 0;
344607259a6SChristoph Hellwig return ip_tunnel_ctl(dev, p, cmd);
3451da177e4SLinus Torvalds }
3461da177e4SLinus Torvalds
34723a12b14SStephen Hemminger static const struct net_device_ops ipip_netdev_ops = {
348fd58156eSPravin B Shelar .ndo_init = ipip_tunnel_init,
349fd58156eSPravin B Shelar .ndo_uninit = ip_tunnel_uninit,
35023a12b14SStephen Hemminger .ndo_start_xmit = ipip_tunnel_xmit,
3513e7a1c7cSArnd Bergmann .ndo_siocdevprivate = ip_tunnel_siocdevprivate,
352fd58156eSPravin B Shelar .ndo_change_mtu = ip_tunnel_change_mtu,
35398d7fc46SHeiner Kallweit .ndo_get_stats64 = dev_get_tstats64,
3541e99584bSNicolas Dichtel .ndo_get_iflink = ip_tunnel_get_iflink,
355607259a6SChristoph Hellwig .ndo_tunnel_ctl = ipip_tunnel_ctl,
35623a12b14SStephen Hemminger };
35723a12b14SStephen Hemminger
358c3b89fbbSEric Dumazet #define IPIP_FEATURES (NETIF_F_SG | \
359c3b89fbbSEric Dumazet NETIF_F_FRAGLIST | \
360c3b89fbbSEric Dumazet NETIF_F_HIGHDMA | \
361cb32f511SEric Dumazet NETIF_F_GSO_SOFTWARE | \
362c3b89fbbSEric Dumazet NETIF_F_HW_CSUM)
363c3b89fbbSEric Dumazet
ipip_tunnel_setup(struct net_device * dev)3641da177e4SLinus Torvalds static void ipip_tunnel_setup(struct net_device *dev)
3651da177e4SLinus Torvalds {
36623a12b14SStephen Hemminger dev->netdev_ops = &ipip_netdev_ops;
367e53ac932SJason A. Donenfeld dev->header_ops = &ip_tunnel_header_ops;
3681da177e4SLinus Torvalds
3691da177e4SLinus Torvalds dev->type = ARPHRD_TUNNEL;
3701da177e4SLinus Torvalds dev->flags = IFF_NOARP;
3711da177e4SLinus Torvalds dev->addr_len = 4;
372153f0943SEric Dumazet dev->features |= NETIF_F_LLTX;
37302875878SEric Dumazet netif_keep_dst(dev);
374c3b89fbbSEric Dumazet
375c3b89fbbSEric Dumazet dev->features |= IPIP_FEATURES;
376c3b89fbbSEric Dumazet dev->hw_features |= IPIP_FEATURES;
377fd58156eSPravin B Shelar ip_tunnel_setup(dev, ipip_net_id);
3781da177e4SLinus Torvalds }
3791da177e4SLinus Torvalds
ipip_tunnel_init(struct net_device * dev)3803c97af99SEric Dumazet static int ipip_tunnel_init(struct net_device *dev)
3811da177e4SLinus Torvalds {
38223a12b14SStephen Hemminger struct ip_tunnel *tunnel = netdev_priv(dev);
3831da177e4SLinus Torvalds
3845a1b7e1aSJakub Kicinski __dev_addr_set(dev, &tunnel->parms.iph.saddr, 4);
3851da177e4SLinus Torvalds memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4);
3861da177e4SLinus Torvalds
387473ab820STom Herbert tunnel->tun_hlen = 0;
388473ab820STom Herbert tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen;
389fd58156eSPravin B Shelar return ip_tunnel_init(dev);
3901da177e4SLinus Torvalds }
3911da177e4SLinus Torvalds
ipip_tunnel_validate(struct nlattr * tb[],struct nlattr * data[],struct netlink_ext_ack * extack)392a8b8a889SMatthias Schiffer static int ipip_tunnel_validate(struct nlattr *tb[], struct nlattr *data[],
393a8b8a889SMatthias Schiffer struct netlink_ext_ack *extack)
3941b69e7e6SSimon Horman {
3951b69e7e6SSimon Horman u8 proto;
3961b69e7e6SSimon Horman
3971b69e7e6SSimon Horman if (!data || !data[IFLA_IPTUN_PROTO])
3981b69e7e6SSimon Horman return 0;
3991b69e7e6SSimon Horman
4001b69e7e6SSimon Horman proto = nla_get_u8(data[IFLA_IPTUN_PROTO]);
4011b69e7e6SSimon Horman if (proto != IPPROTO_IPIP && proto != IPPROTO_MPLS && proto != 0)
4021b69e7e6SSimon Horman return -EINVAL;
4031b69e7e6SSimon Horman
4041b69e7e6SSimon Horman return 0;
4051b69e7e6SSimon Horman }
4061b69e7e6SSimon Horman
ipip_netlink_parms(struct nlattr * data[],struct ip_tunnel_parm * parms,bool * collect_md,__u32 * fwmark)407be42da0eSNicolas Dichtel static void ipip_netlink_parms(struct nlattr *data[],
4089830ad4cSCraig Gallek struct ip_tunnel_parm *parms, bool *collect_md,
4099830ad4cSCraig Gallek __u32 *fwmark)
410be42da0eSNicolas Dichtel {
411be42da0eSNicolas Dichtel memset(parms, 0, sizeof(*parms));
412be42da0eSNicolas Dichtel
413be42da0eSNicolas Dichtel parms->iph.version = 4;
414be42da0eSNicolas Dichtel parms->iph.protocol = IPPROTO_IPIP;
415be42da0eSNicolas Dichtel parms->iph.ihl = 5;
416cfc7381bSAlexei Starovoitov *collect_md = false;
417be42da0eSNicolas Dichtel
418be42da0eSNicolas Dichtel if (!data)
419be42da0eSNicolas Dichtel return;
420be42da0eSNicolas Dichtel
421b86fca80SLiu Jian ip_tunnel_netlink_parms(data, parms);
422cfc7381bSAlexei Starovoitov
423cfc7381bSAlexei Starovoitov if (data[IFLA_IPTUN_COLLECT_METADATA])
424cfc7381bSAlexei Starovoitov *collect_md = true;
4259830ad4cSCraig Gallek
4269830ad4cSCraig Gallek if (data[IFLA_IPTUN_FWMARK])
4279830ad4cSCraig Gallek *fwmark = nla_get_u32(data[IFLA_IPTUN_FWMARK]);
428be42da0eSNicolas Dichtel }
429be42da0eSNicolas Dichtel
ipip_newlink(struct net * src_net,struct net_device * dev,struct nlattr * tb[],struct nlattr * data[],struct netlink_ext_ack * extack)430be42da0eSNicolas Dichtel static int ipip_newlink(struct net *src_net, struct net_device *dev,
4317a3f4a18SMatthias Schiffer struct nlattr *tb[], struct nlattr *data[],
4327a3f4a18SMatthias Schiffer struct netlink_ext_ack *extack)
433be42da0eSNicolas Dichtel {
434cfc7381bSAlexei Starovoitov struct ip_tunnel *t = netdev_priv(dev);
435fd58156eSPravin B Shelar struct ip_tunnel_parm p;
436473ab820STom Herbert struct ip_tunnel_encap ipencap;
4379830ad4cSCraig Gallek __u32 fwmark = 0;
438473ab820STom Herbert
439537dd2d9SLiu Jian if (ip_tunnel_netlink_encap_parms(data, &ipencap)) {
440473ab820STom Herbert int err = ip_tunnel_encap_setup(t, &ipencap);
441473ab820STom Herbert
442473ab820STom Herbert if (err < 0)
443473ab820STom Herbert return err;
444473ab820STom Herbert }
445be42da0eSNicolas Dichtel
4469830ad4cSCraig Gallek ipip_netlink_parms(data, &p, &t->collect_md, &fwmark);
4479830ad4cSCraig Gallek return ip_tunnel_newlink(dev, tb, &p, fwmark);
448be42da0eSNicolas Dichtel }
449be42da0eSNicolas Dichtel
ipip_changelink(struct net_device * dev,struct nlattr * tb[],struct nlattr * data[],struct netlink_ext_ack * extack)450be42da0eSNicolas Dichtel static int ipip_changelink(struct net_device *dev, struct nlattr *tb[],
451ad744b22SMatthias Schiffer struct nlattr *data[],
452ad744b22SMatthias Schiffer struct netlink_ext_ack *extack)
453be42da0eSNicolas Dichtel {
4549830ad4cSCraig Gallek struct ip_tunnel *t = netdev_priv(dev);
455be42da0eSNicolas Dichtel struct ip_tunnel_parm p;
456473ab820STom Herbert struct ip_tunnel_encap ipencap;
457cfc7381bSAlexei Starovoitov bool collect_md;
4589830ad4cSCraig Gallek __u32 fwmark = t->fwmark;
459473ab820STom Herbert
460537dd2d9SLiu Jian if (ip_tunnel_netlink_encap_parms(data, &ipencap)) {
461473ab820STom Herbert int err = ip_tunnel_encap_setup(t, &ipencap);
462473ab820STom Herbert
463473ab820STom Herbert if (err < 0)
464473ab820STom Herbert return err;
465473ab820STom Herbert }
466be42da0eSNicolas Dichtel
4679830ad4cSCraig Gallek ipip_netlink_parms(data, &p, &collect_md, &fwmark);
468cfc7381bSAlexei Starovoitov if (collect_md)
469cfc7381bSAlexei Starovoitov return -EINVAL;
470be42da0eSNicolas Dichtel
471be42da0eSNicolas Dichtel if (((dev->flags & IFF_POINTOPOINT) && !p.iph.daddr) ||
472be42da0eSNicolas Dichtel (!(dev->flags & IFF_POINTOPOINT) && p.iph.daddr))
473be42da0eSNicolas Dichtel return -EINVAL;
474be42da0eSNicolas Dichtel
4759830ad4cSCraig Gallek return ip_tunnel_changelink(dev, tb, &p, fwmark);
476be42da0eSNicolas Dichtel }
477be42da0eSNicolas Dichtel
ipip_get_size(const struct net_device * dev)4780974658dSNicolas Dichtel static size_t ipip_get_size(const struct net_device *dev)
4790974658dSNicolas Dichtel {
4800974658dSNicolas Dichtel return
4810974658dSNicolas Dichtel /* IFLA_IPTUN_LINK */
4820974658dSNicolas Dichtel nla_total_size(4) +
4830974658dSNicolas Dichtel /* IFLA_IPTUN_LOCAL */
4840974658dSNicolas Dichtel nla_total_size(4) +
4850974658dSNicolas Dichtel /* IFLA_IPTUN_REMOTE */
4860974658dSNicolas Dichtel nla_total_size(4) +
4870974658dSNicolas Dichtel /* IFLA_IPTUN_TTL */
4880974658dSNicolas Dichtel nla_total_size(1) +
4890974658dSNicolas Dichtel /* IFLA_IPTUN_TOS */
4900974658dSNicolas Dichtel nla_total_size(1) +
4911b69e7e6SSimon Horman /* IFLA_IPTUN_PROTO */
4921b69e7e6SSimon Horman nla_total_size(1) +
493befe2aa1SNicolas Dichtel /* IFLA_IPTUN_PMTUDISC */
494befe2aa1SNicolas Dichtel nla_total_size(1) +
495473ab820STom Herbert /* IFLA_IPTUN_ENCAP_TYPE */
496473ab820STom Herbert nla_total_size(2) +
497473ab820STom Herbert /* IFLA_IPTUN_ENCAP_FLAGS */
498473ab820STom Herbert nla_total_size(2) +
499473ab820STom Herbert /* IFLA_IPTUN_ENCAP_SPORT */
500473ab820STom Herbert nla_total_size(2) +
501473ab820STom Herbert /* IFLA_IPTUN_ENCAP_DPORT */
502473ab820STom Herbert nla_total_size(2) +
503cfc7381bSAlexei Starovoitov /* IFLA_IPTUN_COLLECT_METADATA */
504cfc7381bSAlexei Starovoitov nla_total_size(0) +
5059830ad4cSCraig Gallek /* IFLA_IPTUN_FWMARK */
5069830ad4cSCraig Gallek nla_total_size(4) +
5070974658dSNicolas Dichtel 0;
5080974658dSNicolas Dichtel }
5090974658dSNicolas Dichtel
ipip_fill_info(struct sk_buff * skb,const struct net_device * dev)5100974658dSNicolas Dichtel static int ipip_fill_info(struct sk_buff *skb, const struct net_device *dev)
5110974658dSNicolas Dichtel {
5120974658dSNicolas Dichtel struct ip_tunnel *tunnel = netdev_priv(dev);
5130974658dSNicolas Dichtel struct ip_tunnel_parm *parm = &tunnel->parms;
5140974658dSNicolas Dichtel
5150974658dSNicolas Dichtel if (nla_put_u32(skb, IFLA_IPTUN_LINK, parm->link) ||
516930345eaSJiri Benc nla_put_in_addr(skb, IFLA_IPTUN_LOCAL, parm->iph.saddr) ||
517930345eaSJiri Benc nla_put_in_addr(skb, IFLA_IPTUN_REMOTE, parm->iph.daddr) ||
5180974658dSNicolas Dichtel nla_put_u8(skb, IFLA_IPTUN_TTL, parm->iph.ttl) ||
519befe2aa1SNicolas Dichtel nla_put_u8(skb, IFLA_IPTUN_TOS, parm->iph.tos) ||
5201b69e7e6SSimon Horman nla_put_u8(skb, IFLA_IPTUN_PROTO, parm->iph.protocol) ||
521befe2aa1SNicolas Dichtel nla_put_u8(skb, IFLA_IPTUN_PMTUDISC,
5229830ad4cSCraig Gallek !!(parm->iph.frag_off & htons(IP_DF))) ||
5239830ad4cSCraig Gallek nla_put_u32(skb, IFLA_IPTUN_FWMARK, tunnel->fwmark))
5240974658dSNicolas Dichtel goto nla_put_failure;
525473ab820STom Herbert
526473ab820STom Herbert if (nla_put_u16(skb, IFLA_IPTUN_ENCAP_TYPE,
527473ab820STom Herbert tunnel->encap.type) ||
5283e97fa70SSabrina Dubroca nla_put_be16(skb, IFLA_IPTUN_ENCAP_SPORT,
529473ab820STom Herbert tunnel->encap.sport) ||
5303e97fa70SSabrina Dubroca nla_put_be16(skb, IFLA_IPTUN_ENCAP_DPORT,
531473ab820STom Herbert tunnel->encap.dport) ||
532473ab820STom Herbert nla_put_u16(skb, IFLA_IPTUN_ENCAP_FLAGS,
533e1b2cb65STom Herbert tunnel->encap.flags))
534473ab820STom Herbert goto nla_put_failure;
535473ab820STom Herbert
536cfc7381bSAlexei Starovoitov if (tunnel->collect_md)
537cfc7381bSAlexei Starovoitov if (nla_put_flag(skb, IFLA_IPTUN_COLLECT_METADATA))
538cfc7381bSAlexei Starovoitov goto nla_put_failure;
5390974658dSNicolas Dichtel return 0;
5400974658dSNicolas Dichtel
5410974658dSNicolas Dichtel nla_put_failure:
5420974658dSNicolas Dichtel return -EMSGSIZE;
5430974658dSNicolas Dichtel }
5440974658dSNicolas Dichtel
545be42da0eSNicolas Dichtel static const struct nla_policy ipip_policy[IFLA_IPTUN_MAX + 1] = {
546be42da0eSNicolas Dichtel [IFLA_IPTUN_LINK] = { .type = NLA_U32 },
547be42da0eSNicolas Dichtel [IFLA_IPTUN_LOCAL] = { .type = NLA_U32 },
548be42da0eSNicolas Dichtel [IFLA_IPTUN_REMOTE] = { .type = NLA_U32 },
549be42da0eSNicolas Dichtel [IFLA_IPTUN_TTL] = { .type = NLA_U8 },
550be42da0eSNicolas Dichtel [IFLA_IPTUN_TOS] = { .type = NLA_U8 },
5511b69e7e6SSimon Horman [IFLA_IPTUN_PROTO] = { .type = NLA_U8 },
552be42da0eSNicolas Dichtel [IFLA_IPTUN_PMTUDISC] = { .type = NLA_U8 },
553473ab820STom Herbert [IFLA_IPTUN_ENCAP_TYPE] = { .type = NLA_U16 },
554473ab820STom Herbert [IFLA_IPTUN_ENCAP_FLAGS] = { .type = NLA_U16 },
555473ab820STom Herbert [IFLA_IPTUN_ENCAP_SPORT] = { .type = NLA_U16 },
556473ab820STom Herbert [IFLA_IPTUN_ENCAP_DPORT] = { .type = NLA_U16 },
557cfc7381bSAlexei Starovoitov [IFLA_IPTUN_COLLECT_METADATA] = { .type = NLA_FLAG },
5589830ad4cSCraig Gallek [IFLA_IPTUN_FWMARK] = { .type = NLA_U32 },
559be42da0eSNicolas Dichtel };
560be42da0eSNicolas Dichtel
5610974658dSNicolas Dichtel static struct rtnl_link_ops ipip_link_ops __read_mostly = {
5620974658dSNicolas Dichtel .kind = "ipip",
5630974658dSNicolas Dichtel .maxtype = IFLA_IPTUN_MAX,
564be42da0eSNicolas Dichtel .policy = ipip_policy,
5650974658dSNicolas Dichtel .priv_size = sizeof(struct ip_tunnel),
566be42da0eSNicolas Dichtel .setup = ipip_tunnel_setup,
5671b69e7e6SSimon Horman .validate = ipip_tunnel_validate,
568be42da0eSNicolas Dichtel .newlink = ipip_newlink,
569be42da0eSNicolas Dichtel .changelink = ipip_changelink,
570fd58156eSPravin B Shelar .dellink = ip_tunnel_dellink,
5710974658dSNicolas Dichtel .get_size = ipip_get_size,
5720974658dSNicolas Dichtel .fill_info = ipip_fill_info,
5731728d4faSNicolas Dichtel .get_link_net = ip_tunnel_get_link_net,
5740974658dSNicolas Dichtel };
5750974658dSNicolas Dichtel
5766dcd814bSEric Dumazet static struct xfrm_tunnel ipip_handler __read_mostly = {
5771da177e4SLinus Torvalds .handler = ipip_rcv,
5781da177e4SLinus Torvalds .err_handler = ipip_err,
579d2acc347SHerbert Xu .priority = 1,
5801da177e4SLinus Torvalds };
5811da177e4SLinus Torvalds
5821b69e7e6SSimon Horman #if IS_ENABLED(CONFIG_MPLS)
5831b69e7e6SSimon Horman static struct xfrm_tunnel mplsip_handler __read_mostly = {
5841b69e7e6SSimon Horman .handler = mplsip_rcv,
5851b69e7e6SSimon Horman .err_handler = ipip_err,
5861b69e7e6SSimon Horman .priority = 1,
5871b69e7e6SSimon Horman };
5881b69e7e6SSimon Horman #endif
5891b69e7e6SSimon Horman
ipip_init_net(struct net * net)5902c8c1e72SAlexey Dobriyan static int __net_init ipip_init_net(struct net *net)
59110dc4c7bSPavel Emelyanov {
592fd58156eSPravin B Shelar return ip_tunnel_init_net(net, ipip_net_id, &ipip_link_ops, "tunl0");
59310dc4c7bSPavel Emelyanov }
59410dc4c7bSPavel Emelyanov
ipip_exit_batch_net(struct list_head * list_net)59564bc1781SEric Dumazet static void __net_exit ipip_exit_batch_net(struct list_head *list_net)
59610dc4c7bSPavel Emelyanov {
59764bc1781SEric Dumazet ip_tunnel_delete_nets(list_net, ipip_net_id, &ipip_link_ops);
59810dc4c7bSPavel Emelyanov }
59910dc4c7bSPavel Emelyanov
60010dc4c7bSPavel Emelyanov static struct pernet_operations ipip_net_ops = {
60110dc4c7bSPavel Emelyanov .init = ipip_init_net,
60264bc1781SEric Dumazet .exit_batch = ipip_exit_batch_net,
60386de8a63SEric W. Biederman .id = &ipip_net_id,
604fd58156eSPravin B Shelar .size = sizeof(struct ip_tunnel_net),
60510dc4c7bSPavel Emelyanov };
60610dc4c7bSPavel Emelyanov
ipip_init(void)6071da177e4SLinus Torvalds static int __init ipip_init(void)
6081da177e4SLinus Torvalds {
6091da177e4SLinus Torvalds int err;
6101da177e4SLinus Torvalds
6111b69e7e6SSimon Horman pr_info("ipip: IPv4 and MPLS over IPv4 tunneling driver\n");
6121da177e4SLinus Torvalds
61386de8a63SEric W. Biederman err = register_pernet_device(&ipip_net_ops);
614d5aa407fSAlexey Dobriyan if (err < 0)
615d5aa407fSAlexey Dobriyan return err;
616d5aa407fSAlexey Dobriyan err = xfrm4_tunnel_register(&ipip_handler, AF_INET);
617d5aa407fSAlexey Dobriyan if (err < 0) {
618058bd4d2SJoe Perches pr_info("%s: can't register tunnel\n", __func__);
6191b69e7e6SSimon Horman goto xfrm_tunnel_ipip_failed;
620d5aa407fSAlexey Dobriyan }
6211b69e7e6SSimon Horman #if IS_ENABLED(CONFIG_MPLS)
6221b69e7e6SSimon Horman err = xfrm4_tunnel_register(&mplsip_handler, AF_MPLS);
6231b69e7e6SSimon Horman if (err < 0) {
6241b69e7e6SSimon Horman pr_info("%s: can't register tunnel\n", __func__);
6251b69e7e6SSimon Horman goto xfrm_tunnel_mplsip_failed;
6261b69e7e6SSimon Horman }
6271b69e7e6SSimon Horman #endif
6280974658dSNicolas Dichtel err = rtnl_link_register(&ipip_link_ops);
6290974658dSNicolas Dichtel if (err < 0)
6300974658dSNicolas Dichtel goto rtnl_link_failed;
6310974658dSNicolas Dichtel
6320974658dSNicolas Dichtel out:
633b9855c54SPavel Emelyanov return err;
6340974658dSNicolas Dichtel
6350974658dSNicolas Dichtel rtnl_link_failed:
6361b69e7e6SSimon Horman #if IS_ENABLED(CONFIG_MPLS)
63757ebc8f0SVadim Fedorenko xfrm4_tunnel_deregister(&mplsip_handler, AF_MPLS);
6381b69e7e6SSimon Horman xfrm_tunnel_mplsip_failed:
6391b69e7e6SSimon Horman
6401b69e7e6SSimon Horman #endif
6410974658dSNicolas Dichtel xfrm4_tunnel_deregister(&ipip_handler, AF_INET);
6421b69e7e6SSimon Horman xfrm_tunnel_ipip_failed:
6430974658dSNicolas Dichtel unregister_pernet_device(&ipip_net_ops);
6440974658dSNicolas Dichtel goto out;
6451da177e4SLinus Torvalds }
6461da177e4SLinus Torvalds
ipip_fini(void)6471da177e4SLinus Torvalds static void __exit ipip_fini(void)
6481da177e4SLinus Torvalds {
6490974658dSNicolas Dichtel rtnl_link_unregister(&ipip_link_ops);
650c0d56408SKazunori MIYAZAWA if (xfrm4_tunnel_deregister(&ipip_handler, AF_INET))
651058bd4d2SJoe Perches pr_info("%s: can't deregister tunnel\n", __func__);
6521b69e7e6SSimon Horman #if IS_ENABLED(CONFIG_MPLS)
6531b69e7e6SSimon Horman if (xfrm4_tunnel_deregister(&mplsip_handler, AF_MPLS))
6541b69e7e6SSimon Horman pr_info("%s: can't deregister tunnel\n", __func__);
6551b69e7e6SSimon Horman #endif
65686de8a63SEric W. Biederman unregister_pernet_device(&ipip_net_ops);
6571da177e4SLinus Torvalds }
6581da177e4SLinus Torvalds
6591da177e4SLinus Torvalds module_init(ipip_init);
6601da177e4SLinus Torvalds module_exit(ipip_fini);
6611da177e4SLinus Torvalds MODULE_LICENSE("GPL");
662f98f89a0STom Gundersen MODULE_ALIAS_RTNL_LINK("ipip");
6638909c9adSVasiliy Kulikov MODULE_ALIAS_NETDEV("tunl0");
664