1c9422999SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2c5441932SPravin B Shelar /*
3c5441932SPravin B Shelar * Copyright (c) 2013 Nicira, Inc.
4c5441932SPravin B Shelar */
5c5441932SPravin B Shelar
6c5441932SPravin B Shelar #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
7c5441932SPravin B Shelar
8c5441932SPravin B Shelar #include <linux/capability.h>
9c5441932SPravin B Shelar #include <linux/module.h>
10c5441932SPravin B Shelar #include <linux/types.h>
11c5441932SPravin B Shelar #include <linux/kernel.h>
12c5441932SPravin B Shelar #include <linux/slab.h>
13c5441932SPravin B Shelar #include <linux/uaccess.h>
14c5441932SPravin B Shelar #include <linux/skbuff.h>
15c5441932SPravin B Shelar #include <linux/netdevice.h>
16c5441932SPravin B Shelar #include <linux/in.h>
17c5441932SPravin B Shelar #include <linux/tcp.h>
18c5441932SPravin B Shelar #include <linux/udp.h>
19c5441932SPravin B Shelar #include <linux/if_arp.h>
20c5441932SPravin B Shelar #include <linux/init.h>
21c5441932SPravin B Shelar #include <linux/in6.h>
22c5441932SPravin B Shelar #include <linux/inetdevice.h>
23c5441932SPravin B Shelar #include <linux/igmp.h>
24c5441932SPravin B Shelar #include <linux/netfilter_ipv4.h>
25c5441932SPravin B Shelar #include <linux/etherdevice.h>
26c5441932SPravin B Shelar #include <linux/if_ether.h>
27c5441932SPravin B Shelar #include <linux/if_vlan.h>
28c5441932SPravin B Shelar #include <linux/rculist.h>
2927d79f3bSSachin Kamat #include <linux/err.h>
30c5441932SPravin B Shelar
31c5441932SPravin B Shelar #include <net/sock.h>
32c5441932SPravin B Shelar #include <net/ip.h>
33c5441932SPravin B Shelar #include <net/icmp.h>
34c5441932SPravin B Shelar #include <net/protocol.h>
35c5441932SPravin B Shelar #include <net/ip_tunnels.h>
36c5441932SPravin B Shelar #include <net/arp.h>
37c5441932SPravin B Shelar #include <net/checksum.h>
38c5441932SPravin B Shelar #include <net/dsfield.h>
39c5441932SPravin B Shelar #include <net/inet_ecn.h>
40c5441932SPravin B Shelar #include <net/xfrm.h>
41c5441932SPravin B Shelar #include <net/net_namespace.h>
42c5441932SPravin B Shelar #include <net/netns/generic.h>
438ef890dfSJakub Kicinski #include <net/netdev_lock.h>
44c5441932SPravin B Shelar #include <net/rtnetlink.h>
4556328486STom Herbert #include <net/udp.h>
46cfc7381bSAlexei Starovoitov #include <net/dst_metadata.h>
47c34cfe72SIdo Schimmel #include <net/inet_dscp.h>
4863487babSTom Herbert
49c5441932SPravin B Shelar #if IS_ENABLED(CONFIG_IPV6)
50c5441932SPravin B Shelar #include <net/ipv6.h>
51c5441932SPravin B Shelar #include <net/ip6_fib.h>
52c5441932SPravin B Shelar #include <net/ip6_route.h>
53c5441932SPravin B Shelar #endif
54c5441932SPravin B Shelar
ip_tunnel_hash(__be32 key,__be32 remote)55967680e0SDuan Jiong static unsigned int ip_tunnel_hash(__be32 key, __be32 remote)
56c5441932SPravin B Shelar {
57c5441932SPravin B Shelar return hash_32((__force u32)key ^ (__force u32)remote,
58c5441932SPravin B Shelar IP_TNL_HASH_BITS);
59c5441932SPravin B Shelar }
60c5441932SPravin B Shelar
ip_tunnel_key_match(const struct ip_tunnel_parm_kern * p,const unsigned long * flags,__be32 key)61117aef12SAlexander Lobakin static bool ip_tunnel_key_match(const struct ip_tunnel_parm_kern *p,
625832c4a7SAlexander Lobakin const unsigned long *flags, __be32 key)
63c5441932SPravin B Shelar {
645832c4a7SAlexander Lobakin if (!test_bit(IP_TUNNEL_KEY_BIT, flags))
655832c4a7SAlexander Lobakin return !test_bit(IP_TUNNEL_KEY_BIT, p->i_flags);
665832c4a7SAlexander Lobakin
675832c4a7SAlexander Lobakin return test_bit(IP_TUNNEL_KEY_BIT, p->i_flags) && p->i_key == key;
68c5441932SPravin B Shelar }
69c5441932SPravin B Shelar
70c5441932SPravin B Shelar /* Fallback tunnel: no source, no destination, no key, no options
71c5441932SPravin B Shelar
72c5441932SPravin B Shelar Tunnel hash table:
73c5441932SPravin B Shelar We require exact key match i.e. if a key is present in packet
74c5441932SPravin B Shelar it will match only tunnel with the same key; if it is not present,
75c5441932SPravin B Shelar it will match only keyless tunnel.
76c5441932SPravin B Shelar
77c5441932SPravin B Shelar All keysless packets, if not matched configured keyless tunnels
78c5441932SPravin B Shelar will match fallback tunnel.
79c5441932SPravin B Shelar Given src, dst and key, find appropriate for input tunnel.
80c5441932SPravin B Shelar */
ip_tunnel_lookup(struct ip_tunnel_net * itn,int link,const unsigned long * flags,__be32 remote,__be32 local,__be32 key)81c5441932SPravin B Shelar struct ip_tunnel *ip_tunnel_lookup(struct ip_tunnel_net *itn,
825832c4a7SAlexander Lobakin int link, const unsigned long *flags,
83c5441932SPravin B Shelar __be32 remote, __be32 local,
84c5441932SPravin B Shelar __be32 key)
85c5441932SPravin B Shelar {
86c5441932SPravin B Shelar struct ip_tunnel *t, *cand = NULL;
87c5441932SPravin B Shelar struct hlist_head *head;
88ba61539cSTaehee Yoo struct net_device *ndev;
89ba61539cSTaehee Yoo unsigned int hash;
90c5441932SPravin B Shelar
91967680e0SDuan Jiong hash = ip_tunnel_hash(key, remote);
92c5441932SPravin B Shelar head = &itn->tunnels[hash];
93c5441932SPravin B Shelar
94c5441932SPravin B Shelar hlist_for_each_entry_rcu(t, head, hash_node) {
95c5441932SPravin B Shelar if (local != t->parms.iph.saddr ||
96c5441932SPravin B Shelar remote != t->parms.iph.daddr ||
97c5441932SPravin B Shelar !(t->dev->flags & IFF_UP))
98c5441932SPravin B Shelar continue;
99c5441932SPravin B Shelar
100c5441932SPravin B Shelar if (!ip_tunnel_key_match(&t->parms, flags, key))
101c5441932SPravin B Shelar continue;
102c5441932SPravin B Shelar
103f694eee9SEric Dumazet if (READ_ONCE(t->parms.link) == link)
104c5441932SPravin B Shelar return t;
105c5441932SPravin B Shelar cand = t;
106c5441932SPravin B Shelar }
107c5441932SPravin B Shelar
108c5441932SPravin B Shelar hlist_for_each_entry_rcu(t, head, hash_node) {
109c5441932SPravin B Shelar if (remote != t->parms.iph.daddr ||
110e0056593SDmitry Popov t->parms.iph.saddr != 0 ||
111c5441932SPravin B Shelar !(t->dev->flags & IFF_UP))
112c5441932SPravin B Shelar continue;
113c5441932SPravin B Shelar
114c5441932SPravin B Shelar if (!ip_tunnel_key_match(&t->parms, flags, key))
115c5441932SPravin B Shelar continue;
116c5441932SPravin B Shelar
117f694eee9SEric Dumazet if (READ_ONCE(t->parms.link) == link)
118c5441932SPravin B Shelar return t;
119f694eee9SEric Dumazet if (!cand)
120c5441932SPravin B Shelar cand = t;
121c5441932SPravin B Shelar }
122c5441932SPravin B Shelar
123967680e0SDuan Jiong hash = ip_tunnel_hash(key, 0);
124c5441932SPravin B Shelar head = &itn->tunnels[hash];
125c5441932SPravin B Shelar
126c5441932SPravin B Shelar hlist_for_each_entry_rcu(t, head, hash_node) {
127e0056593SDmitry Popov if ((local != t->parms.iph.saddr || t->parms.iph.daddr != 0) &&
128e0056593SDmitry Popov (local != t->parms.iph.daddr || !ipv4_is_multicast(local)))
129e0056593SDmitry Popov continue;
130e0056593SDmitry Popov
131e0056593SDmitry Popov if (!(t->dev->flags & IFF_UP))
132c5441932SPravin B Shelar continue;
133c5441932SPravin B Shelar
134c5441932SPravin B Shelar if (!ip_tunnel_key_match(&t->parms, flags, key))
135c5441932SPravin B Shelar continue;
136c5441932SPravin B Shelar
137f694eee9SEric Dumazet if (READ_ONCE(t->parms.link) == link)
138c5441932SPravin B Shelar return t;
139f694eee9SEric Dumazet if (!cand)
140c5441932SPravin B Shelar cand = t;
141c5441932SPravin B Shelar }
142c5441932SPravin B Shelar
143c5441932SPravin B Shelar hlist_for_each_entry_rcu(t, head, hash_node) {
1445832c4a7SAlexander Lobakin if ((!test_bit(IP_TUNNEL_NO_KEY_BIT, flags) &&
1455832c4a7SAlexander Lobakin t->parms.i_key != key) ||
146e0056593SDmitry Popov t->parms.iph.saddr != 0 ||
147e0056593SDmitry Popov t->parms.iph.daddr != 0 ||
148c5441932SPravin B Shelar !(t->dev->flags & IFF_UP))
149c5441932SPravin B Shelar continue;
150c5441932SPravin B Shelar
151f694eee9SEric Dumazet if (READ_ONCE(t->parms.link) == link)
152c5441932SPravin B Shelar return t;
153f694eee9SEric Dumazet if (!cand)
154c5441932SPravin B Shelar cand = t;
155c5441932SPravin B Shelar }
156c5441932SPravin B Shelar
157c5441932SPravin B Shelar if (cand)
158c5441932SPravin B Shelar return cand;
159c5441932SPravin B Shelar
1602e15ea39SPravin B Shelar t = rcu_dereference(itn->collect_md_tun);
161833a8b40SHaishuang Yan if (t && t->dev->flags & IFF_UP)
1622e15ea39SPravin B Shelar return t;
1632e15ea39SPravin B Shelar
164ba61539cSTaehee Yoo ndev = READ_ONCE(itn->fb_tunnel_dev);
165ba61539cSTaehee Yoo if (ndev && ndev->flags & IFF_UP)
166ba61539cSTaehee Yoo return netdev_priv(ndev);
167c5441932SPravin B Shelar
168c5441932SPravin B Shelar return NULL;
169c5441932SPravin B Shelar }
170c5441932SPravin B Shelar EXPORT_SYMBOL_GPL(ip_tunnel_lookup);
171c5441932SPravin B Shelar
ip_bucket(struct ip_tunnel_net * itn,struct ip_tunnel_parm_kern * parms)172c5441932SPravin B Shelar static struct hlist_head *ip_bucket(struct ip_tunnel_net *itn,
173117aef12SAlexander Lobakin struct ip_tunnel_parm_kern *parms)
174c5441932SPravin B Shelar {
175c5441932SPravin B Shelar unsigned int h;
176c5441932SPravin B Shelar __be32 remote;
1776d608f06SSteffen Klassert __be32 i_key = parms->i_key;
178c5441932SPravin B Shelar
179c5441932SPravin B Shelar if (parms->iph.daddr && !ipv4_is_multicast(parms->iph.daddr))
180c5441932SPravin B Shelar remote = parms->iph.daddr;
181c5441932SPravin B Shelar else
182c5441932SPravin B Shelar remote = 0;
183c5441932SPravin B Shelar
1845832c4a7SAlexander Lobakin if (!test_bit(IP_TUNNEL_KEY_BIT, parms->i_flags) &&
1855832c4a7SAlexander Lobakin test_bit(IP_TUNNEL_VTI_BIT, parms->i_flags))
1866d608f06SSteffen Klassert i_key = 0;
1876d608f06SSteffen Klassert
1886d608f06SSteffen Klassert h = ip_tunnel_hash(i_key, remote);
189c5441932SPravin B Shelar return &itn->tunnels[h];
190c5441932SPravin B Shelar }
191c5441932SPravin B Shelar
ip_tunnel_add(struct ip_tunnel_net * itn,struct ip_tunnel * t)192c5441932SPravin B Shelar static void ip_tunnel_add(struct ip_tunnel_net *itn, struct ip_tunnel *t)
193c5441932SPravin B Shelar {
194c5441932SPravin B Shelar struct hlist_head *head = ip_bucket(itn, &t->parms);
195c5441932SPravin B Shelar
1962e15ea39SPravin B Shelar if (t->collect_md)
1972e15ea39SPravin B Shelar rcu_assign_pointer(itn->collect_md_tun, t);
198c5441932SPravin B Shelar hlist_add_head_rcu(&t->hash_node, head);
199c5441932SPravin B Shelar }
200c5441932SPravin B Shelar
ip_tunnel_del(struct ip_tunnel_net * itn,struct ip_tunnel * t)2012e15ea39SPravin B Shelar static void ip_tunnel_del(struct ip_tunnel_net *itn, struct ip_tunnel *t)
202c5441932SPravin B Shelar {
2032e15ea39SPravin B Shelar if (t->collect_md)
2042e15ea39SPravin B Shelar rcu_assign_pointer(itn->collect_md_tun, NULL);
205c5441932SPravin B Shelar hlist_del_init_rcu(&t->hash_node);
206c5441932SPravin B Shelar }
207c5441932SPravin B Shelar
ip_tunnel_find(struct ip_tunnel_net * itn,struct ip_tunnel_parm_kern * parms,int type)208c5441932SPravin B Shelar static struct ip_tunnel *ip_tunnel_find(struct ip_tunnel_net *itn,
209117aef12SAlexander Lobakin struct ip_tunnel_parm_kern *parms,
210c5441932SPravin B Shelar int type)
211c5441932SPravin B Shelar {
212c5441932SPravin B Shelar __be32 remote = parms->iph.daddr;
213c5441932SPravin B Shelar __be32 local = parms->iph.saddr;
2145832c4a7SAlexander Lobakin IP_TUNNEL_DECLARE_FLAGS(flags);
215c5441932SPravin B Shelar __be32 key = parms->i_key;
216c5441932SPravin B Shelar int link = parms->link;
217c5441932SPravin B Shelar struct ip_tunnel *t = NULL;
218c5441932SPravin B Shelar struct hlist_head *head = ip_bucket(itn, parms);
219c5441932SPravin B Shelar
2205832c4a7SAlexander Lobakin ip_tunnel_flags_copy(flags, parms->i_flags);
2215832c4a7SAlexander Lobakin
22290e0569dSIdo Schimmel hlist_for_each_entry_rcu(t, head, hash_node, lockdep_rtnl_is_held()) {
223c5441932SPravin B Shelar if (local == t->parms.iph.saddr &&
224c5441932SPravin B Shelar remote == t->parms.iph.daddr &&
225f694eee9SEric Dumazet link == READ_ONCE(t->parms.link) &&
2265ce54af1SDmitry Popov type == t->dev->type &&
2275ce54af1SDmitry Popov ip_tunnel_key_match(&t->parms, flags, key))
228c5441932SPravin B Shelar break;
229c5441932SPravin B Shelar }
230c5441932SPravin B Shelar return t;
231c5441932SPravin B Shelar }
232c5441932SPravin B Shelar
__ip_tunnel_create(struct net * net,const struct rtnl_link_ops * ops,struct ip_tunnel_parm_kern * parms)233c5441932SPravin B Shelar static struct net_device *__ip_tunnel_create(struct net *net,
234c5441932SPravin B Shelar const struct rtnl_link_ops *ops,
235117aef12SAlexander Lobakin struct ip_tunnel_parm_kern *parms)
236c5441932SPravin B Shelar {
237c5441932SPravin B Shelar int err;
238c5441932SPravin B Shelar struct ip_tunnel *tunnel;
239c5441932SPravin B Shelar struct net_device *dev;
240c5441932SPravin B Shelar char name[IFNAMSIZ];
241c5441932SPravin B Shelar
242c5441932SPravin B Shelar err = -E2BIG;
2439cb726a2SEric Dumazet if (parms->name[0]) {
2449cb726a2SEric Dumazet if (!dev_valid_name(parms->name))
245c5441932SPravin B Shelar goto failed;
246*c2dbda07SRuben Wauters strscpy(name, parms->name);
2479cb726a2SEric Dumazet } else {
2489cb726a2SEric Dumazet if (strlen(ops->kind) > (IFNAMSIZ - 3))
2499cb726a2SEric Dumazet goto failed;
250*c2dbda07SRuben Wauters strscpy(name, ops->kind);
251000ade80SSultan Alsawaf strcat(name, "%d");
252c5441932SPravin B Shelar }
253c5441932SPravin B Shelar
254c5441932SPravin B Shelar ASSERT_RTNL();
255c835a677STom Gundersen dev = alloc_netdev(ops->priv_size, name, NET_NAME_UNKNOWN, ops->setup);
256c5441932SPravin B Shelar if (!dev) {
257c5441932SPravin B Shelar err = -ENOMEM;
258c5441932SPravin B Shelar goto failed;
259c5441932SPravin B Shelar }
260c5441932SPravin B Shelar dev_net_set(dev, net);
261c5441932SPravin B Shelar
262c5441932SPravin B Shelar dev->rtnl_link_ops = ops;
263c5441932SPravin B Shelar
264c5441932SPravin B Shelar tunnel = netdev_priv(dev);
265c5441932SPravin B Shelar tunnel->parms = *parms;
2665e6700b3SNicolas Dichtel tunnel->net = net;
267c5441932SPravin B Shelar
268c5441932SPravin B Shelar err = register_netdevice(dev);
269c5441932SPravin B Shelar if (err)
270c5441932SPravin B Shelar goto failed_free;
271c5441932SPravin B Shelar
272c5441932SPravin B Shelar return dev;
273c5441932SPravin B Shelar
274c5441932SPravin B Shelar failed_free:
275c5441932SPravin B Shelar free_netdev(dev);
276c5441932SPravin B Shelar failed:
277c5441932SPravin B Shelar return ERR_PTR(err);
278c5441932SPravin B Shelar }
279c5441932SPravin B Shelar
ip_tunnel_bind_dev(struct net_device * dev)280c5441932SPravin B Shelar static int ip_tunnel_bind_dev(struct net_device *dev)
281c5441932SPravin B Shelar {
282c5441932SPravin B Shelar struct net_device *tdev = NULL;
283c5441932SPravin B Shelar struct ip_tunnel *tunnel = netdev_priv(dev);
284c5441932SPravin B Shelar const struct iphdr *iph;
285c5441932SPravin B Shelar int hlen = LL_MAX_HEADER;
286c5441932SPravin B Shelar int mtu = ETH_DATA_LEN;
287c5441932SPravin B Shelar int t_hlen = tunnel->hlen + sizeof(struct iphdr);
288c5441932SPravin B Shelar
289c5441932SPravin B Shelar iph = &tunnel->parms.iph;
290c5441932SPravin B Shelar
291c5441932SPravin B Shelar /* Guess output device to choose reasonable mtu and needed_headroom */
292c5441932SPravin B Shelar if (iph->daddr) {
293c5441932SPravin B Shelar struct flowi4 fl4;
294c5441932SPravin B Shelar struct rtable *rt;
295c5441932SPravin B Shelar
296b0066da5SPetr Machata ip_tunnel_init_flow(&fl4, iph->protocol, iph->daddr,
2977d442fabSTom Herbert iph->saddr, tunnel->parms.o_key,
298b5a7b661SXiao Liang iph->tos & INET_DSCP_MASK, tunnel->net,
2997ec9fce4SEyal Birger tunnel->parms.link, tunnel->fwmark, 0, 0);
3007d442fabSTom Herbert rt = ip_route_output_key(tunnel->net, &fl4);
3017d442fabSTom Herbert
302c5441932SPravin B Shelar if (!IS_ERR(rt)) {
303c5441932SPravin B Shelar tdev = rt->dst.dev;
304c5441932SPravin B Shelar ip_rt_put(rt);
305c5441932SPravin B Shelar }
306c5441932SPravin B Shelar if (dev->type != ARPHRD_ETHER)
307c5441932SPravin B Shelar dev->flags |= IFF_POINTOPOINT;
308f27337e1SPaolo Abeni
309f27337e1SPaolo Abeni dst_cache_reset(&tunnel->dst_cache);
310c5441932SPravin B Shelar }
311c5441932SPravin B Shelar
312c5441932SPravin B Shelar if (!tdev && tunnel->parms.link)
3136c742e71SNicolas Dichtel tdev = __dev_get_by_index(tunnel->net, tunnel->parms.link);
314c5441932SPravin B Shelar
315c5441932SPravin B Shelar if (tdev) {
316c5441932SPravin B Shelar hlen = tdev->hard_header_len + tdev->needed_headroom;
31782612de1SNicolas Dichtel mtu = min(tdev->mtu, IP_MAX_MTU);
318c5441932SPravin B Shelar }
319c5441932SPravin B Shelar
320c5441932SPravin B Shelar dev->needed_headroom = t_hlen + hlen;
3219992a078SHangbin Liu mtu -= t_hlen + (dev->type == ARPHRD_ETHER ? dev->hard_header_len : 0);
322c5441932SPravin B Shelar
323b5476022SEric Dumazet if (mtu < IPV4_MIN_MTU)
324b5476022SEric Dumazet mtu = IPV4_MIN_MTU;
325c5441932SPravin B Shelar
326c5441932SPravin B Shelar return mtu;
327c5441932SPravin B Shelar }
328c5441932SPravin B Shelar
ip_tunnel_create(struct net * net,struct ip_tunnel_net * itn,struct ip_tunnel_parm_kern * parms)329c5441932SPravin B Shelar static struct ip_tunnel *ip_tunnel_create(struct net *net,
330c5441932SPravin B Shelar struct ip_tunnel_net *itn,
331117aef12SAlexander Lobakin struct ip_tunnel_parm_kern *parms)
332c5441932SPravin B Shelar {
3334929fd8cSJulia Lawall struct ip_tunnel *nt;
334c5441932SPravin B Shelar struct net_device *dev;
335b96f9afeSJarod Wilson int t_hlen;
336f6cc9c05SPetr Machata int mtu;
337f6cc9c05SPetr Machata int err;
338c5441932SPravin B Shelar
33979134e6cSEric Dumazet dev = __ip_tunnel_create(net, itn->rtnl_link_ops, parms);
340c5441932SPravin B Shelar if (IS_ERR(dev))
3416dd3c9ecSFlorian Westphal return ERR_CAST(dev);
342c5441932SPravin B Shelar
343f6cc9c05SPetr Machata mtu = ip_tunnel_bind_dev(dev);
344f6cc9c05SPetr Machata err = dev_set_mtu(dev, mtu);
345f6cc9c05SPetr Machata if (err)
346f6cc9c05SPetr Machata goto err_dev_set_mtu;
347c5441932SPravin B Shelar
348c5441932SPravin B Shelar nt = netdev_priv(dev);
349b96f9afeSJarod Wilson t_hlen = nt->hlen + sizeof(struct iphdr);
350b96f9afeSJarod Wilson dev->min_mtu = ETH_MIN_MTU;
35128e104d0SVadim Fedorenko dev->max_mtu = IP_MAX_MTU - t_hlen;
3529992a078SHangbin Liu if (dev->type == ARPHRD_ETHER)
3539992a078SHangbin Liu dev->max_mtu -= dev->hard_header_len;
3549992a078SHangbin Liu
355c5441932SPravin B Shelar ip_tunnel_add(itn, nt);
356c5441932SPravin B Shelar return nt;
357f6cc9c05SPetr Machata
358f6cc9c05SPetr Machata err_dev_set_mtu:
359f6cc9c05SPetr Machata unregister_netdevice(dev);
360f6cc9c05SPetr Machata return ERR_PTR(err);
361c5441932SPravin B Shelar }
362c5441932SPravin B Shelar
ip_tunnel_md_udp_encap(struct sk_buff * skb,struct ip_tunnel_info * info)363ac931d4cSChristian Ehrig void ip_tunnel_md_udp_encap(struct sk_buff *skb, struct ip_tunnel_info *info)
364ac931d4cSChristian Ehrig {
365ac931d4cSChristian Ehrig const struct iphdr *iph = ip_hdr(skb);
366ac931d4cSChristian Ehrig const struct udphdr *udph;
367ac931d4cSChristian Ehrig
368ac931d4cSChristian Ehrig if (iph->protocol != IPPROTO_UDP)
369ac931d4cSChristian Ehrig return;
370ac931d4cSChristian Ehrig
371ac931d4cSChristian Ehrig udph = (struct udphdr *)((__u8 *)iph + (iph->ihl << 2));
372ac931d4cSChristian Ehrig info->encap.sport = udph->source;
373ac931d4cSChristian Ehrig info->encap.dport = udph->dest;
374ac931d4cSChristian Ehrig }
375ac931d4cSChristian Ehrig EXPORT_SYMBOL(ip_tunnel_md_udp_encap);
376ac931d4cSChristian Ehrig
ip_tunnel_rcv(struct ip_tunnel * tunnel,struct sk_buff * skb,const struct tnl_ptk_info * tpi,struct metadata_dst * tun_dst,bool log_ecn_error)377c5441932SPravin B Shelar int ip_tunnel_rcv(struct ip_tunnel *tunnel, struct sk_buff *skb,
3782e15ea39SPravin B Shelar const struct tnl_ptk_info *tpi, struct metadata_dst *tun_dst,
3792e15ea39SPravin B Shelar bool log_ecn_error)
380c5441932SPravin B Shelar {
381c5441932SPravin B Shelar const struct iphdr *iph = ip_hdr(skb);
382b0ec2abfSEric Dumazet int nh, err;
383c5441932SPravin B Shelar
384c5441932SPravin B Shelar #ifdef CONFIG_NET_IPGRE_BROADCAST
385c5441932SPravin B Shelar if (ipv4_is_multicast(iph->daddr)) {
386c4794d22SEric Dumazet DEV_STATS_INC(tunnel->dev, multicast);
387c5441932SPravin B Shelar skb->pkt_type = PACKET_BROADCAST;
388c5441932SPravin B Shelar }
389c5441932SPravin B Shelar #endif
390c5441932SPravin B Shelar
3915832c4a7SAlexander Lobakin if (test_bit(IP_TUNNEL_CSUM_BIT, tunnel->parms.i_flags) !=
3925832c4a7SAlexander Lobakin test_bit(IP_TUNNEL_CSUM_BIT, tpi->flags)) {
393c4794d22SEric Dumazet DEV_STATS_INC(tunnel->dev, rx_crc_errors);
394c4794d22SEric Dumazet DEV_STATS_INC(tunnel->dev, rx_errors);
395c5441932SPravin B Shelar goto drop;
396c5441932SPravin B Shelar }
397c5441932SPravin B Shelar
3985832c4a7SAlexander Lobakin if (test_bit(IP_TUNNEL_SEQ_BIT, tunnel->parms.i_flags)) {
3995832c4a7SAlexander Lobakin if (!test_bit(IP_TUNNEL_SEQ_BIT, tpi->flags) ||
400c5441932SPravin B Shelar (tunnel->i_seqno && (s32)(ntohl(tpi->seq) - tunnel->i_seqno) < 0)) {
401c4794d22SEric Dumazet DEV_STATS_INC(tunnel->dev, rx_fifo_errors);
402c4794d22SEric Dumazet DEV_STATS_INC(tunnel->dev, rx_errors);
403c5441932SPravin B Shelar goto drop;
404c5441932SPravin B Shelar }
405c5441932SPravin B Shelar tunnel->i_seqno = ntohl(tpi->seq) + 1;
406c5441932SPravin B Shelar }
407c5441932SPravin B Shelar
408b0ec2abfSEric Dumazet /* Save offset of outer header relative to skb->head,
409b0ec2abfSEric Dumazet * because we are going to reset the network header to the inner header
410b0ec2abfSEric Dumazet * and might change skb->head.
411b0ec2abfSEric Dumazet */
412b0ec2abfSEric Dumazet nh = skb_network_header(skb) - skb->head;
413b0ec2abfSEric Dumazet
414227adfb2SGilad Naaman skb_set_network_header(skb, (tunnel->dev->type == ARPHRD_ETHER) ? ETH_HLEN : 0);
415e96f2e7cSYing Cai
416b0ec2abfSEric Dumazet if (!pskb_inet_may_pull(skb)) {
417b0ec2abfSEric Dumazet DEV_STATS_INC(tunnel->dev, rx_length_errors);
418b0ec2abfSEric Dumazet DEV_STATS_INC(tunnel->dev, rx_errors);
419b0ec2abfSEric Dumazet goto drop;
420b0ec2abfSEric Dumazet }
421b0ec2abfSEric Dumazet iph = (struct iphdr *)(skb->head + nh);
422b0ec2abfSEric Dumazet
423c5441932SPravin B Shelar err = IP_ECN_decapsulate(iph, skb);
424c5441932SPravin B Shelar if (unlikely(err)) {
425c5441932SPravin B Shelar if (log_ecn_error)
426c5441932SPravin B Shelar net_info_ratelimited("non-ECT from %pI4 with TOS=%#x\n",
427c5441932SPravin B Shelar &iph->saddr, iph->tos);
428c5441932SPravin B Shelar if (err > 1) {
429c4794d22SEric Dumazet DEV_STATS_INC(tunnel->dev, rx_frame_errors);
430c4794d22SEric Dumazet DEV_STATS_INC(tunnel->dev, rx_errors);
431c5441932SPravin B Shelar goto drop;
432c5441932SPravin B Shelar }
433c5441932SPravin B Shelar }
434c5441932SPravin B Shelar
435560b50cfSFabian Frederick dev_sw_netstats_rx_add(tunnel->dev, skb->len);
43681b9eab5SAlexei Starovoitov skb_scrub_packet(skb, !net_eq(tunnel->net, dev_net(tunnel->dev)));
43781b9eab5SAlexei Starovoitov
4383d7b46cdSPravin B Shelar if (tunnel->dev->type == ARPHRD_ETHER) {
4393d7b46cdSPravin B Shelar skb->protocol = eth_type_trans(skb, tunnel->dev);
4403d7b46cdSPravin B Shelar skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN);
4413d7b46cdSPravin B Shelar } else {
4423d7b46cdSPravin B Shelar skb->dev = tunnel->dev;
4433d7b46cdSPravin B Shelar }
44464261f23SNicolas Dichtel
4452e15ea39SPravin B Shelar if (tun_dst)
4462e15ea39SPravin B Shelar skb_dst_set(skb, (struct dst_entry *)tun_dst);
4472e15ea39SPravin B Shelar
448c5441932SPravin B Shelar gro_cells_receive(&tunnel->gro_cells, skb);
449c5441932SPravin B Shelar return 0;
450c5441932SPravin B Shelar
451c5441932SPravin B Shelar drop:
452469f87e1SHaishuang Yan if (tun_dst)
453469f87e1SHaishuang Yan dst_release((struct dst_entry *)tun_dst);
454c5441932SPravin B Shelar kfree_skb(skb);
455c5441932SPravin B Shelar return 0;
456c5441932SPravin B Shelar }
457c5441932SPravin B Shelar EXPORT_SYMBOL_GPL(ip_tunnel_rcv);
458c5441932SPravin B Shelar
ip_tunnel_encap_add_ops(const struct ip_tunnel_encap_ops * ops,unsigned int num)459a8c5f90fSTom Herbert int ip_tunnel_encap_add_ops(const struct ip_tunnel_encap_ops *ops,
460a8c5f90fSTom Herbert unsigned int num)
461a8c5f90fSTom Herbert {
462bb1553c8SThomas Graf if (num >= MAX_IPTUN_ENCAP_OPS)
463bb1553c8SThomas Graf return -ERANGE;
464bb1553c8SThomas Graf
465a8c5f90fSTom Herbert return !cmpxchg((const struct ip_tunnel_encap_ops **)
466a8c5f90fSTom Herbert &iptun_encaps[num],
467a8c5f90fSTom Herbert NULL, ops) ? 0 : -1;
46856328486STom Herbert }
469a8c5f90fSTom Herbert EXPORT_SYMBOL(ip_tunnel_encap_add_ops);
470a8c5f90fSTom Herbert
ip_tunnel_encap_del_ops(const struct ip_tunnel_encap_ops * ops,unsigned int num)471a8c5f90fSTom Herbert int ip_tunnel_encap_del_ops(const struct ip_tunnel_encap_ops *ops,
472a8c5f90fSTom Herbert unsigned int num)
473a8c5f90fSTom Herbert {
474a8c5f90fSTom Herbert int ret;
475a8c5f90fSTom Herbert
476bb1553c8SThomas Graf if (num >= MAX_IPTUN_ENCAP_OPS)
477bb1553c8SThomas Graf return -ERANGE;
478bb1553c8SThomas Graf
479a8c5f90fSTom Herbert ret = (cmpxchg((const struct ip_tunnel_encap_ops **)
480a8c5f90fSTom Herbert &iptun_encaps[num],
481a8c5f90fSTom Herbert ops, NULL) == ops) ? 0 : -1;
482a8c5f90fSTom Herbert
483a8c5f90fSTom Herbert synchronize_net();
484a8c5f90fSTom Herbert
485a8c5f90fSTom Herbert return ret;
486a8c5f90fSTom Herbert }
487a8c5f90fSTom Herbert EXPORT_SYMBOL(ip_tunnel_encap_del_ops);
48856328486STom Herbert
ip_tunnel_encap_setup(struct ip_tunnel * t,struct ip_tunnel_encap * ipencap)48956328486STom Herbert int ip_tunnel_encap_setup(struct ip_tunnel *t,
49056328486STom Herbert struct ip_tunnel_encap *ipencap)
49156328486STom Herbert {
49256328486STom Herbert int hlen;
49356328486STom Herbert
49456328486STom Herbert memset(&t->encap, 0, sizeof(t->encap));
49556328486STom Herbert
49656328486STom Herbert hlen = ip_encap_hlen(ipencap);
49756328486STom Herbert if (hlen < 0)
49856328486STom Herbert return hlen;
49956328486STom Herbert
50056328486STom Herbert t->encap.type = ipencap->type;
50156328486STom Herbert t->encap.sport = ipencap->sport;
50256328486STom Herbert t->encap.dport = ipencap->dport;
50356328486STom Herbert t->encap.flags = ipencap->flags;
50456328486STom Herbert
50556328486STom Herbert t->encap_hlen = hlen;
50656328486STom Herbert t->hlen = t->encap_hlen + t->tun_hlen;
50756328486STom Herbert
50856328486STom Herbert return 0;
50956328486STom Herbert }
51056328486STom Herbert EXPORT_SYMBOL_GPL(ip_tunnel_encap_setup);
51156328486STom Herbert
tnl_update_pmtu(struct net_device * dev,struct sk_buff * skb,struct rtable * rt,__be16 df,const struct iphdr * inner_iph,int tunnel_hlen,__be32 dst,bool md)51223a3647bSPravin B Shelar static int tnl_update_pmtu(struct net_device *dev, struct sk_buff *skb,
513fc24f2b2STimo Teräs struct rtable *rt, __be16 df,
514c8b34e68Swenxu const struct iphdr *inner_iph,
515c8b34e68Swenxu int tunnel_hlen, __be32 dst, bool md)
51623a3647bSPravin B Shelar {
51723a3647bSPravin B Shelar struct ip_tunnel *tunnel = netdev_priv(dev);
518c8b34e68Swenxu int pkt_size;
51923a3647bSPravin B Shelar int mtu;
52023a3647bSPravin B Shelar
521c8b34e68Swenxu tunnel_hlen = md ? tunnel_hlen : tunnel->hlen;
52228e104d0SVadim Fedorenko pkt_size = skb->len - tunnel_hlen;
5239992a078SHangbin Liu pkt_size -= dev->type == ARPHRD_ETHER ? dev->hard_header_len : 0;
524c8b34e68Swenxu
5259992a078SHangbin Liu if (df) {
52628e104d0SVadim Fedorenko mtu = dst_mtu(&rt->dst) - (sizeof(struct iphdr) + tunnel_hlen);
5279992a078SHangbin Liu mtu -= dev->type == ARPHRD_ETHER ? dev->hard_header_len : 0;
5289992a078SHangbin Liu } else {
529f4b3ec4eSAlan Maguire mtu = skb_valid_dst(skb) ? dst_mtu(skb_dst(skb)) : dev->mtu;
5309992a078SHangbin Liu }
53123a3647bSPravin B Shelar
532f4b3ec4eSAlan Maguire if (skb_valid_dst(skb))
5337a1592bcSHangbin Liu skb_dst_update_pmtu_no_confirm(skb, mtu);
53423a3647bSPravin B Shelar
53523a3647bSPravin B Shelar if (skb->protocol == htons(ETH_P_IP)) {
53623a3647bSPravin B Shelar if (!skb_is_gso(skb) &&
537fc24f2b2STimo Teräs (inner_iph->frag_off & htons(IP_DF)) &&
538fc24f2b2STimo Teräs mtu < pkt_size) {
5394372339eSJason A. Donenfeld icmp_ndo_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));
54023a3647bSPravin B Shelar return -E2BIG;
54123a3647bSPravin B Shelar }
54223a3647bSPravin B Shelar }
54323a3647bSPravin B Shelar #if IS_ENABLED(CONFIG_IPV6)
54423a3647bSPravin B Shelar else if (skb->protocol == htons(ETH_P_IPV6)) {
545f4b3ec4eSAlan Maguire struct rt6_info *rt6;
546c8b34e68Swenxu __be32 daddr;
547c8b34e68Swenxu
548e8dfd42cSEric Dumazet rt6 = skb_valid_dst(skb) ? dst_rt6_info(skb_dst(skb)) :
549f4b3ec4eSAlan Maguire NULL;
550c8b34e68Swenxu daddr = md ? dst : tunnel->parms.iph.daddr;
55123a3647bSPravin B Shelar
55223a3647bSPravin B Shelar if (rt6 && mtu < dst_mtu(skb_dst(skb)) &&
55323a3647bSPravin B Shelar mtu >= IPV6_MIN_MTU) {
554c8b34e68Swenxu if ((daddr && !ipv4_is_multicast(daddr)) ||
55523a3647bSPravin B Shelar rt6->rt6i_dst.plen == 128) {
55623a3647bSPravin B Shelar rt6->rt6i_flags |= RTF_MODIFIED;
55723a3647bSPravin B Shelar dst_metric_set(skb_dst(skb), RTAX_MTU, mtu);
55823a3647bSPravin B Shelar }
55923a3647bSPravin B Shelar }
56023a3647bSPravin B Shelar
56123a3647bSPravin B Shelar if (!skb_is_gso(skb) && mtu >= IPV6_MIN_MTU &&
56223a3647bSPravin B Shelar mtu < pkt_size) {
5634372339eSJason A. Donenfeld icmpv6_ndo_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
56423a3647bSPravin B Shelar return -E2BIG;
56523a3647bSPravin B Shelar }
56623a3647bSPravin B Shelar }
56723a3647bSPravin B Shelar #endif
56823a3647bSPravin B Shelar return 0;
56923a3647bSPravin B Shelar }
57023a3647bSPravin B Shelar
ip_tunnel_adj_headroom(struct net_device * dev,unsigned int headroom)5715ae1e992SFlorian Westphal static void ip_tunnel_adj_headroom(struct net_device *dev, unsigned int headroom)
5725ae1e992SFlorian Westphal {
5735ae1e992SFlorian Westphal /* we must cap headroom to some upperlimit, else pskb_expand_head
5745ae1e992SFlorian Westphal * will overflow header offsets in skb_headers_offset_update().
5755ae1e992SFlorian Westphal */
5765ae1e992SFlorian Westphal static const unsigned int max_allowed = 512;
5775ae1e992SFlorian Westphal
5785ae1e992SFlorian Westphal if (headroom > max_allowed)
5795ae1e992SFlorian Westphal headroom = max_allowed;
5805ae1e992SFlorian Westphal
5815ae1e992SFlorian Westphal if (headroom > READ_ONCE(dev->needed_headroom))
5825ae1e992SFlorian Westphal WRITE_ONCE(dev->needed_headroom, headroom);
5835ae1e992SFlorian Westphal }
5845ae1e992SFlorian Westphal
ip_md_tunnel_xmit(struct sk_buff * skb,struct net_device * dev,u8 proto,int tunnel_hlen)585c8b34e68Swenxu void ip_md_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
586c8b34e68Swenxu u8 proto, int tunnel_hlen)
587cfc7381bSAlexei Starovoitov {
588cfc7381bSAlexei Starovoitov struct ip_tunnel *tunnel = netdev_priv(dev);
589cfc7381bSAlexei Starovoitov u32 headroom = sizeof(struct iphdr);
590cfc7381bSAlexei Starovoitov struct ip_tunnel_info *tun_info;
591cfc7381bSAlexei Starovoitov const struct ip_tunnel_key *key;
592cfc7381bSAlexei Starovoitov const struct iphdr *inner_iph;
593f46fe4f8Swenxu struct rtable *rt = NULL;
594cfc7381bSAlexei Starovoitov struct flowi4 fl4;
595cfc7381bSAlexei Starovoitov __be16 df = 0;
596cfc7381bSAlexei Starovoitov u8 tos, ttl;
597f46fe4f8Swenxu bool use_cache;
598cfc7381bSAlexei Starovoitov
599cfc7381bSAlexei Starovoitov tun_info = skb_tunnel_info(skb);
600cfc7381bSAlexei Starovoitov if (unlikely(!tun_info || !(tun_info->mode & IP_TUNNEL_INFO_TX) ||
601cfc7381bSAlexei Starovoitov ip_tunnel_info_af(tun_info) != AF_INET))
602cfc7381bSAlexei Starovoitov goto tx_error;
603cfc7381bSAlexei Starovoitov key = &tun_info->key;
604cfc7381bSAlexei Starovoitov memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
605cfc7381bSAlexei Starovoitov inner_iph = (const struct iphdr *)skb_inner_network_header(skb);
606cfc7381bSAlexei Starovoitov tos = key->tos;
607cfc7381bSAlexei Starovoitov if (tos == 1) {
608cfc7381bSAlexei Starovoitov if (skb->protocol == htons(ETH_P_IP))
609cfc7381bSAlexei Starovoitov tos = inner_iph->tos;
610cfc7381bSAlexei Starovoitov else if (skb->protocol == htons(ETH_P_IPV6))
611cfc7381bSAlexei Starovoitov tos = ipv6_get_dsfield((const struct ipv6hdr *)inner_iph);
612cfc7381bSAlexei Starovoitov }
6136e6b904aSwenxu ip_tunnel_init_flow(&fl4, proto, key->u.ipv4.dst, key->u.ipv4.src,
614c34cfe72SIdo Schimmel tunnel_id_to_key32(key->tun_id),
615b5a7b661SXiao Liang tos & INET_DSCP_MASK, tunnel->net, 0, skb->mark,
616c34cfe72SIdo Schimmel skb_get_hash(skb), key->flow_flags);
617ac931d4cSChristian Ehrig
618ac931d4cSChristian Ehrig if (!tunnel_hlen)
619ac931d4cSChristian Ehrig tunnel_hlen = ip_encap_hlen(&tun_info->encap);
620ac931d4cSChristian Ehrig
621ac931d4cSChristian Ehrig if (ip_tunnel_encap(skb, &tun_info->encap, &proto, &fl4) < 0)
622cfc7381bSAlexei Starovoitov goto tx_error;
623f46fe4f8Swenxu
624f46fe4f8Swenxu use_cache = ip_tunnel_dst_cache_usable(skb, tun_info);
625f46fe4f8Swenxu if (use_cache)
626f46fe4f8Swenxu rt = dst_cache_get_ip4(&tun_info->dst_cache, &fl4.saddr);
627f46fe4f8Swenxu if (!rt) {
628cfc7381bSAlexei Starovoitov rt = ip_route_output_key(tunnel->net, &fl4);
629cfc7381bSAlexei Starovoitov if (IS_ERR(rt)) {
630c4794d22SEric Dumazet DEV_STATS_INC(dev, tx_carrier_errors);
631cfc7381bSAlexei Starovoitov goto tx_error;
632cfc7381bSAlexei Starovoitov }
633f46fe4f8Swenxu if (use_cache)
634f46fe4f8Swenxu dst_cache_set_ip4(&tun_info->dst_cache, &rt->dst,
635f46fe4f8Swenxu fl4.saddr);
636f46fe4f8Swenxu }
637cfc7381bSAlexei Starovoitov if (rt->dst.dev == dev) {
638cfc7381bSAlexei Starovoitov ip_rt_put(rt);
639c4794d22SEric Dumazet DEV_STATS_INC(dev, collisions);
640cfc7381bSAlexei Starovoitov goto tx_error;
641cfc7381bSAlexei Starovoitov }
642c8b34e68Swenxu
6435832c4a7SAlexander Lobakin if (test_bit(IP_TUNNEL_DONT_FRAGMENT_BIT, key->tun_flags))
644c8b34e68Swenxu df = htons(IP_DF);
645c8b34e68Swenxu if (tnl_update_pmtu(dev, skb, rt, df, inner_iph, tunnel_hlen,
646c8b34e68Swenxu key->u.ipv4.dst, true)) {
647c8b34e68Swenxu ip_rt_put(rt);
648c8b34e68Swenxu goto tx_error;
649c8b34e68Swenxu }
650c8b34e68Swenxu
651cfc7381bSAlexei Starovoitov tos = ip_tunnel_ecn_encap(tos, inner_iph, skb);
652cfc7381bSAlexei Starovoitov ttl = key->ttl;
653cfc7381bSAlexei Starovoitov if (ttl == 0) {
654cfc7381bSAlexei Starovoitov if (skb->protocol == htons(ETH_P_IP))
655cfc7381bSAlexei Starovoitov ttl = inner_iph->ttl;
656cfc7381bSAlexei Starovoitov else if (skb->protocol == htons(ETH_P_IPV6))
657cfc7381bSAlexei Starovoitov ttl = ((const struct ipv6hdr *)inner_iph)->hop_limit;
658cfc7381bSAlexei Starovoitov else
659cfc7381bSAlexei Starovoitov ttl = ip4_dst_hoplimit(&rt->dst);
660cfc7381bSAlexei Starovoitov }
661c8b34e68Swenxu
662cfc7381bSAlexei Starovoitov headroom += LL_RESERVED_SPACE(rt->dst.dev) + rt->dst.header_len;
6635ae1e992SFlorian Westphal if (skb_cow_head(skb, headroom)) {
664cfc7381bSAlexei Starovoitov ip_rt_put(rt);
665cfc7381bSAlexei Starovoitov goto tx_dropped;
666cfc7381bSAlexei Starovoitov }
6675ae1e992SFlorian Westphal
6685ae1e992SFlorian Westphal ip_tunnel_adj_headroom(dev, headroom);
6695ae1e992SFlorian Westphal
6700f693f19SHaishuang Yan iptunnel_xmit(NULL, rt, skb, fl4.saddr, fl4.daddr, proto, tos, ttl,
6710f693f19SHaishuang Yan df, !net_eq(tunnel->net, dev_net(dev)), 0);
672cfc7381bSAlexei Starovoitov return;
673cfc7381bSAlexei Starovoitov tx_error:
674c4794d22SEric Dumazet DEV_STATS_INC(dev, tx_errors);
675cfc7381bSAlexei Starovoitov goto kfree;
676cfc7381bSAlexei Starovoitov tx_dropped:
677c4794d22SEric Dumazet DEV_STATS_INC(dev, tx_dropped);
678cfc7381bSAlexei Starovoitov kfree:
679cfc7381bSAlexei Starovoitov kfree_skb(skb);
680cfc7381bSAlexei Starovoitov }
681cfc7381bSAlexei Starovoitov EXPORT_SYMBOL_GPL(ip_md_tunnel_xmit);
682cfc7381bSAlexei Starovoitov
ip_tunnel_xmit(struct sk_buff * skb,struct net_device * dev,const struct iphdr * tnl_params,u8 protocol)683c5441932SPravin B Shelar void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
68456328486STom Herbert const struct iphdr *tnl_params, u8 protocol)
685c5441932SPravin B Shelar {
686c5441932SPravin B Shelar struct ip_tunnel *tunnel = netdev_priv(dev);
687186d9366Swenxu struct ip_tunnel_info *tun_info = NULL;
688c5441932SPravin B Shelar const struct iphdr *inner_iph;
689c5441932SPravin B Shelar unsigned int max_headroom; /* The extra header space needed */
690186d9366Swenxu struct rtable *rt = NULL; /* Route to the other host */
6917ae29fd1SMatthias May __be16 payload_protocol;
692186d9366Swenxu bool use_cache = false;
693186d9366Swenxu struct flowi4 fl4;
694186d9366Swenxu bool md = false;
69522fb22eaSTimo Teräs bool connected;
696186d9366Swenxu u8 tos, ttl;
697186d9366Swenxu __be32 dst;
698186d9366Swenxu __be16 df;
699c5441932SPravin B Shelar
700c5441932SPravin B Shelar inner_iph = (const struct iphdr *)skb_inner_network_header(skb);
70122fb22eaSTimo Teräs connected = (tunnel->parms.iph.daddr != 0);
7027ae29fd1SMatthias May payload_protocol = skb_protocol(skb, true);
703c5441932SPravin B Shelar
7045146d1f1SBernie Harris memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
7055146d1f1SBernie Harris
706c5441932SPravin B Shelar dst = tnl_params->daddr;
707c5441932SPravin B Shelar if (dst == 0) {
708c5441932SPravin B Shelar /* NBMA tunnel */
709c5441932SPravin B Shelar
71051456b29SIan Morris if (!skb_dst(skb)) {
711c4794d22SEric Dumazet DEV_STATS_INC(dev, tx_fifo_errors);
712c5441932SPravin B Shelar goto tx_error;
713c5441932SPravin B Shelar }
714c5441932SPravin B Shelar
715d71b5753Swenxu tun_info = skb_tunnel_info(skb);
716d71b5753Swenxu if (tun_info && (tun_info->mode & IP_TUNNEL_INFO_TX) &&
717d71b5753Swenxu ip_tunnel_info_af(tun_info) == AF_INET &&
718186d9366Swenxu tun_info->key.u.ipv4.dst) {
719d71b5753Swenxu dst = tun_info->key.u.ipv4.dst;
720186d9366Swenxu md = true;
721186d9366Swenxu connected = true;
7227ae29fd1SMatthias May } else if (payload_protocol == htons(ETH_P_IP)) {
723c5441932SPravin B Shelar rt = skb_rtable(skb);
724c5441932SPravin B Shelar dst = rt_nexthop(rt, inner_iph->daddr);
725c5441932SPravin B Shelar }
726c5441932SPravin B Shelar #if IS_ENABLED(CONFIG_IPV6)
7277ae29fd1SMatthias May else if (payload_protocol == htons(ETH_P_IPV6)) {
728c5441932SPravin B Shelar const struct in6_addr *addr6;
729c5441932SPravin B Shelar struct neighbour *neigh;
730c5441932SPravin B Shelar bool do_tx_error_icmp;
731c5441932SPravin B Shelar int addr_type;
732c5441932SPravin B Shelar
733c5441932SPravin B Shelar neigh = dst_neigh_lookup(skb_dst(skb),
734c5441932SPravin B Shelar &ipv6_hdr(skb)->daddr);
73551456b29SIan Morris if (!neigh)
736c5441932SPravin B Shelar goto tx_error;
737c5441932SPravin B Shelar
738c5441932SPravin B Shelar addr6 = (const struct in6_addr *)&neigh->primary_key;
739c5441932SPravin B Shelar addr_type = ipv6_addr_type(addr6);
740c5441932SPravin B Shelar
741c5441932SPravin B Shelar if (addr_type == IPV6_ADDR_ANY) {
742c5441932SPravin B Shelar addr6 = &ipv6_hdr(skb)->daddr;
743c5441932SPravin B Shelar addr_type = ipv6_addr_type(addr6);
744c5441932SPravin B Shelar }
745c5441932SPravin B Shelar
746c5441932SPravin B Shelar if ((addr_type & IPV6_ADDR_COMPATv4) == 0)
747c5441932SPravin B Shelar do_tx_error_icmp = true;
748c5441932SPravin B Shelar else {
749c5441932SPravin B Shelar do_tx_error_icmp = false;
750c5441932SPravin B Shelar dst = addr6->s6_addr32[3];
751c5441932SPravin B Shelar }
752c5441932SPravin B Shelar neigh_release(neigh);
753c5441932SPravin B Shelar if (do_tx_error_icmp)
754c5441932SPravin B Shelar goto tx_error_icmp;
755c5441932SPravin B Shelar }
756c5441932SPravin B Shelar #endif
757c5441932SPravin B Shelar else
758c5441932SPravin B Shelar goto tx_error;
7597d442fabSTom Herbert
760186d9366Swenxu if (!md)
7617d442fabSTom Herbert connected = false;
762c5441932SPravin B Shelar }
763c5441932SPravin B Shelar
764c5441932SPravin B Shelar tos = tnl_params->tos;
765c5441932SPravin B Shelar if (tos & 0x1) {
766c5441932SPravin B Shelar tos &= ~0x1;
7677ae29fd1SMatthias May if (payload_protocol == htons(ETH_P_IP)) {
768c5441932SPravin B Shelar tos = inner_iph->tos;
7697d442fabSTom Herbert connected = false;
7707ae29fd1SMatthias May } else if (payload_protocol == htons(ETH_P_IPV6)) {
771c5441932SPravin B Shelar tos = ipv6_get_dsfield((const struct ipv6hdr *)inner_iph);
7727d442fabSTom Herbert connected = false;
7737d442fabSTom Herbert }
774c5441932SPravin B Shelar }
775c5441932SPravin B Shelar
776b0066da5SPetr Machata ip_tunnel_init_flow(&fl4, protocol, dst, tnl_params->saddr,
777c2b639f9SIdo Schimmel tunnel->parms.o_key, tos & INET_DSCP_MASK,
778b5a7b661SXiao Liang tunnel->net, READ_ONCE(tunnel->parms.link),
7797ec9fce4SEyal Birger tunnel->fwmark, skb_get_hash(skb), 0);
7807d442fabSTom Herbert
781ac931d4cSChristian Ehrig if (ip_tunnel_encap(skb, &tunnel->encap, &protocol, &fl4) < 0)
78256328486STom Herbert goto tx_error;
78356328486STom Herbert
784186d9366Swenxu if (connected && md) {
785186d9366Swenxu use_cache = ip_tunnel_dst_cache_usable(skb, tun_info);
786186d9366Swenxu if (use_cache)
787186d9366Swenxu rt = dst_cache_get_ip4(&tun_info->dst_cache,
788186d9366Swenxu &fl4.saddr);
789186d9366Swenxu } else {
790186d9366Swenxu rt = connected ? dst_cache_get_ip4(&tunnel->dst_cache,
791186d9366Swenxu &fl4.saddr) : NULL;
792186d9366Swenxu }
7937d442fabSTom Herbert
7947d442fabSTom Herbert if (!rt) {
7957d442fabSTom Herbert rt = ip_route_output_key(tunnel->net, &fl4);
7967d442fabSTom Herbert
797c5441932SPravin B Shelar if (IS_ERR(rt)) {
798c4794d22SEric Dumazet DEV_STATS_INC(dev, tx_carrier_errors);
799c5441932SPravin B Shelar goto tx_error;
800c5441932SPravin B Shelar }
801186d9366Swenxu if (use_cache)
802186d9366Swenxu dst_cache_set_ip4(&tun_info->dst_cache, &rt->dst,
803186d9366Swenxu fl4.saddr);
804186d9366Swenxu else if (!md && connected)
805e09acddfSPaolo Abeni dst_cache_set_ip4(&tunnel->dst_cache, &rt->dst,
806e09acddfSPaolo Abeni fl4.saddr);
8077d442fabSTom Herbert }
8087d442fabSTom Herbert
8090e6fbc5bSPravin B Shelar if (rt->dst.dev == dev) {
810c5441932SPravin B Shelar ip_rt_put(rt);
811c4794d22SEric Dumazet DEV_STATS_INC(dev, collisions);
812c5441932SPravin B Shelar goto tx_error;
813c5441932SPravin B Shelar }
814c5441932SPravin B Shelar
81550c66167SFlorian Westphal df = tnl_params->frag_off;
8167ae29fd1SMatthias May if (payload_protocol == htons(ETH_P_IP) && !tunnel->ignore_df)
81750c66167SFlorian Westphal df |= (inner_iph->frag_off & htons(IP_DF));
81850c66167SFlorian Westphal
81950c66167SFlorian Westphal if (tnl_update_pmtu(dev, skb, rt, df, inner_iph, 0, 0, false)) {
820c5441932SPravin B Shelar ip_rt_put(rt);
821c5441932SPravin B Shelar goto tx_error;
822c5441932SPravin B Shelar }
823c5441932SPravin B Shelar
824c5441932SPravin B Shelar if (tunnel->err_count > 0) {
825c5441932SPravin B Shelar if (time_before(jiffies,
826c5441932SPravin B Shelar tunnel->err_time + IPTUNNEL_ERR_TIMEO)) {
827c5441932SPravin B Shelar tunnel->err_count--;
828c5441932SPravin B Shelar
829c5441932SPravin B Shelar dst_link_failure(skb);
830c5441932SPravin B Shelar } else
831c5441932SPravin B Shelar tunnel->err_count = 0;
832c5441932SPravin B Shelar }
833c5441932SPravin B Shelar
834d4a71b15SPravin B Shelar tos = ip_tunnel_ecn_encap(tos, inner_iph, skb);
835c5441932SPravin B Shelar ttl = tnl_params->ttl;
836c5441932SPravin B Shelar if (ttl == 0) {
8377ae29fd1SMatthias May if (payload_protocol == htons(ETH_P_IP))
838c5441932SPravin B Shelar ttl = inner_iph->ttl;
839c5441932SPravin B Shelar #if IS_ENABLED(CONFIG_IPV6)
8407ae29fd1SMatthias May else if (payload_protocol == htons(ETH_P_IPV6))
841c5441932SPravin B Shelar ttl = ((const struct ipv6hdr *)inner_iph)->hop_limit;
842c5441932SPravin B Shelar #endif
843c5441932SPravin B Shelar else
844c5441932SPravin B Shelar ttl = ip4_dst_hoplimit(&rt->dst);
845c5441932SPravin B Shelar }
846c5441932SPravin B Shelar
8470e6fbc5bSPravin B Shelar max_headroom = LL_RESERVED_SPACE(rt->dst.dev) + sizeof(struct iphdr)
8487371e022STom Herbert + rt->dst.header_len + ip_encap_hlen(&tunnel->encap);
8493e08f4a7SSteffen Klassert
8505ae1e992SFlorian Westphal if (skb_cow_head(skb, max_headroom)) {
851586d5fc8SDmitry Popov ip_rt_put(rt);
852c4794d22SEric Dumazet DEV_STATS_INC(dev, tx_dropped);
8533acfa1e7SEric Dumazet kfree_skb(skb);
854c5441932SPravin B Shelar return;
855c5441932SPravin B Shelar }
856c5441932SPravin B Shelar
8575ae1e992SFlorian Westphal ip_tunnel_adj_headroom(dev, max_headroom);
8585ae1e992SFlorian Westphal
859039f5062SPravin B Shelar iptunnel_xmit(NULL, rt, skb, fl4.saddr, fl4.daddr, protocol, tos, ttl,
860039f5062SPravin B Shelar df, !net_eq(tunnel->net, dev_net(dev)), 0);
861c5441932SPravin B Shelar return;
862c5441932SPravin B Shelar
863c5441932SPravin B Shelar #if IS_ENABLED(CONFIG_IPV6)
864c5441932SPravin B Shelar tx_error_icmp:
865c5441932SPravin B Shelar dst_link_failure(skb);
866c5441932SPravin B Shelar #endif
867c5441932SPravin B Shelar tx_error:
868c4794d22SEric Dumazet DEV_STATS_INC(dev, tx_errors);
8693acfa1e7SEric Dumazet kfree_skb(skb);
870c5441932SPravin B Shelar }
871c5441932SPravin B Shelar EXPORT_SYMBOL_GPL(ip_tunnel_xmit);
872c5441932SPravin B Shelar
ip_tunnel_update(struct ip_tunnel_net * itn,struct ip_tunnel * t,struct net_device * dev,struct ip_tunnel_parm_kern * p,bool set_mtu,__u32 fwmark)873c5441932SPravin B Shelar static void ip_tunnel_update(struct ip_tunnel_net *itn,
874c5441932SPravin B Shelar struct ip_tunnel *t,
875c5441932SPravin B Shelar struct net_device *dev,
876117aef12SAlexander Lobakin struct ip_tunnel_parm_kern *p,
8779830ad4cSCraig Gallek bool set_mtu,
8789830ad4cSCraig Gallek __u32 fwmark)
879c5441932SPravin B Shelar {
8802e15ea39SPravin B Shelar ip_tunnel_del(itn, t);
881c5441932SPravin B Shelar t->parms.iph.saddr = p->iph.saddr;
882c5441932SPravin B Shelar t->parms.iph.daddr = p->iph.daddr;
883c5441932SPravin B Shelar t->parms.i_key = p->i_key;
884c5441932SPravin B Shelar t->parms.o_key = p->o_key;
885c5441932SPravin B Shelar if (dev->type != ARPHRD_ETHER) {
8865a1b7e1aSJakub Kicinski __dev_addr_set(dev, &p->iph.saddr, 4);
887c5441932SPravin B Shelar memcpy(dev->broadcast, &p->iph.daddr, 4);
888c5441932SPravin B Shelar }
889c5441932SPravin B Shelar ip_tunnel_add(itn, t);
890c5441932SPravin B Shelar
891c5441932SPravin B Shelar t->parms.iph.ttl = p->iph.ttl;
892c5441932SPravin B Shelar t->parms.iph.tos = p->iph.tos;
893c5441932SPravin B Shelar t->parms.iph.frag_off = p->iph.frag_off;
894c5441932SPravin B Shelar
8959830ad4cSCraig Gallek if (t->parms.link != p->link || t->fwmark != fwmark) {
896c5441932SPravin B Shelar int mtu;
897c5441932SPravin B Shelar
898f694eee9SEric Dumazet WRITE_ONCE(t->parms.link, p->link);
8999830ad4cSCraig Gallek t->fwmark = fwmark;
900c5441932SPravin B Shelar mtu = ip_tunnel_bind_dev(dev);
901c5441932SPravin B Shelar if (set_mtu)
9021eb2cdedSEric Dumazet WRITE_ONCE(dev->mtu, mtu);
903c5441932SPravin B Shelar }
904e09acddfSPaolo Abeni dst_cache_reset(&t->dst_cache);
905c5441932SPravin B Shelar netdev_state_change(dev);
906c5441932SPravin B Shelar }
907c5441932SPravin B Shelar
ip_tunnel_ctl(struct net_device * dev,struct ip_tunnel_parm_kern * p,int cmd)908117aef12SAlexander Lobakin int ip_tunnel_ctl(struct net_device *dev, struct ip_tunnel_parm_kern *p,
909117aef12SAlexander Lobakin int cmd)
910c5441932SPravin B Shelar {
911c5441932SPravin B Shelar int err = 0;
9128c923ce2SNicolas Dichtel struct ip_tunnel *t = netdev_priv(dev);
9138c923ce2SNicolas Dichtel struct net *net = t->net;
9148c923ce2SNicolas Dichtel struct ip_tunnel_net *itn = net_generic(net, t->ip_tnl_net_id);
915c5441932SPravin B Shelar
916c5441932SPravin B Shelar switch (cmd) {
917c5441932SPravin B Shelar case SIOCGETTUNNEL:
9188c923ce2SNicolas Dichtel if (dev == itn->fb_tunnel_dev) {
919c5441932SPravin B Shelar t = ip_tunnel_find(itn, p, itn->fb_tunnel_dev->type);
92051456b29SIan Morris if (!t)
921c5441932SPravin B Shelar t = netdev_priv(dev);
9228c923ce2SNicolas Dichtel }
923c5441932SPravin B Shelar memcpy(p, &t->parms, sizeof(*p));
924c5441932SPravin B Shelar break;
925c5441932SPravin B Shelar
926c5441932SPravin B Shelar case SIOCADDTUNNEL:
927c5441932SPravin B Shelar case SIOCCHGTUNNEL:
928c5441932SPravin B Shelar err = -EPERM;
929c5441932SPravin B Shelar if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
930c5441932SPravin B Shelar goto done;
931c5441932SPravin B Shelar if (p->iph.ttl)
932c5441932SPravin B Shelar p->iph.frag_off |= htons(IP_DF);
9335832c4a7SAlexander Lobakin if (!test_bit(IP_TUNNEL_VTI_BIT, p->i_flags)) {
9345832c4a7SAlexander Lobakin if (!test_bit(IP_TUNNEL_KEY_BIT, p->i_flags))
935c5441932SPravin B Shelar p->i_key = 0;
9365832c4a7SAlexander Lobakin if (!test_bit(IP_TUNNEL_KEY_BIT, p->o_flags))
937c5441932SPravin B Shelar p->o_key = 0;
9387c8e6b9cSDmitry Popov }
939c5441932SPravin B Shelar
94079134e6cSEric Dumazet t = ip_tunnel_find(itn, p, itn->type);
941c5441932SPravin B Shelar
942d61746b2SSteffen Klassert if (cmd == SIOCADDTUNNEL) {
943d61746b2SSteffen Klassert if (!t) {
944c5441932SPravin B Shelar t = ip_tunnel_create(net, itn, p);
945ee30ef4dSDuan Jiong err = PTR_ERR_OR_ZERO(t);
9466dd3c9ecSFlorian Westphal break;
9476dd3c9ecSFlorian Westphal }
948d61746b2SSteffen Klassert
949d61746b2SSteffen Klassert err = -EEXIST;
950d61746b2SSteffen Klassert break;
951d61746b2SSteffen Klassert }
952c5441932SPravin B Shelar if (dev != itn->fb_tunnel_dev && cmd == SIOCCHGTUNNEL) {
95300db4124SIan Morris if (t) {
954c5441932SPravin B Shelar if (t->dev != dev) {
955c5441932SPravin B Shelar err = -EEXIST;
956c5441932SPravin B Shelar break;
957c5441932SPravin B Shelar }
958c5441932SPravin B Shelar } else {
959c5441932SPravin B Shelar unsigned int nflags = 0;
960c5441932SPravin B Shelar
961c5441932SPravin B Shelar if (ipv4_is_multicast(p->iph.daddr))
962c5441932SPravin B Shelar nflags = IFF_BROADCAST;
963c5441932SPravin B Shelar else if (p->iph.daddr)
964c5441932SPravin B Shelar nflags = IFF_POINTOPOINT;
965c5441932SPravin B Shelar
966c5441932SPravin B Shelar if ((dev->flags^nflags)&(IFF_POINTOPOINT|IFF_BROADCAST)) {
967c5441932SPravin B Shelar err = -EINVAL;
968c5441932SPravin B Shelar break;
969c5441932SPravin B Shelar }
970c5441932SPravin B Shelar
971c5441932SPravin B Shelar t = netdev_priv(dev);
972c5441932SPravin B Shelar }
973c5441932SPravin B Shelar }
974c5441932SPravin B Shelar
975c5441932SPravin B Shelar if (t) {
976c5441932SPravin B Shelar err = 0;
9779830ad4cSCraig Gallek ip_tunnel_update(itn, t, dev, p, true, 0);
9786dd3c9ecSFlorian Westphal } else {
9796dd3c9ecSFlorian Westphal err = -ENOENT;
9806dd3c9ecSFlorian Westphal }
981c5441932SPravin B Shelar break;
982c5441932SPravin B Shelar
983c5441932SPravin B Shelar case SIOCDELTUNNEL:
984c5441932SPravin B Shelar err = -EPERM;
985c5441932SPravin B Shelar if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
986c5441932SPravin B Shelar goto done;
987c5441932SPravin B Shelar
988c5441932SPravin B Shelar if (dev == itn->fb_tunnel_dev) {
989c5441932SPravin B Shelar err = -ENOENT;
990c5441932SPravin B Shelar t = ip_tunnel_find(itn, p, itn->fb_tunnel_dev->type);
99151456b29SIan Morris if (!t)
992c5441932SPravin B Shelar goto done;
993c5441932SPravin B Shelar err = -EPERM;
994c5441932SPravin B Shelar if (t == netdev_priv(itn->fb_tunnel_dev))
995c5441932SPravin B Shelar goto done;
996c5441932SPravin B Shelar dev = t->dev;
997c5441932SPravin B Shelar }
998c5441932SPravin B Shelar unregister_netdevice(dev);
999c5441932SPravin B Shelar err = 0;
1000c5441932SPravin B Shelar break;
1001c5441932SPravin B Shelar
1002c5441932SPravin B Shelar default:
1003c5441932SPravin B Shelar err = -EINVAL;
1004c5441932SPravin B Shelar }
1005c5441932SPravin B Shelar
1006c5441932SPravin B Shelar done:
1007c5441932SPravin B Shelar return err;
1008c5441932SPravin B Shelar }
1009607259a6SChristoph Hellwig EXPORT_SYMBOL_GPL(ip_tunnel_ctl);
1010607259a6SChristoph Hellwig
ip_tunnel_parm_from_user(struct ip_tunnel_parm_kern * kp,const void __user * data)1011117aef12SAlexander Lobakin bool ip_tunnel_parm_from_user(struct ip_tunnel_parm_kern *kp,
1012117aef12SAlexander Lobakin const void __user *data)
1013117aef12SAlexander Lobakin {
1014117aef12SAlexander Lobakin struct ip_tunnel_parm p;
1015117aef12SAlexander Lobakin
1016117aef12SAlexander Lobakin if (copy_from_user(&p, data, sizeof(p)))
1017117aef12SAlexander Lobakin return false;
1018117aef12SAlexander Lobakin
1019117aef12SAlexander Lobakin strscpy(kp->name, p.name);
1020117aef12SAlexander Lobakin kp->link = p.link;
10215832c4a7SAlexander Lobakin ip_tunnel_flags_from_be16(kp->i_flags, p.i_flags);
10225832c4a7SAlexander Lobakin ip_tunnel_flags_from_be16(kp->o_flags, p.o_flags);
1023117aef12SAlexander Lobakin kp->i_key = p.i_key;
1024117aef12SAlexander Lobakin kp->o_key = p.o_key;
1025117aef12SAlexander Lobakin memcpy(&kp->iph, &p.iph, min(sizeof(kp->iph), sizeof(p.iph)));
1026117aef12SAlexander Lobakin
1027117aef12SAlexander Lobakin return true;
1028117aef12SAlexander Lobakin }
1029117aef12SAlexander Lobakin EXPORT_SYMBOL_GPL(ip_tunnel_parm_from_user);
1030117aef12SAlexander Lobakin
ip_tunnel_parm_to_user(void __user * data,struct ip_tunnel_parm_kern * kp)1031117aef12SAlexander Lobakin bool ip_tunnel_parm_to_user(void __user *data, struct ip_tunnel_parm_kern *kp)
1032117aef12SAlexander Lobakin {
1033117aef12SAlexander Lobakin struct ip_tunnel_parm p;
1034117aef12SAlexander Lobakin
10355832c4a7SAlexander Lobakin if (!ip_tunnel_flags_is_be16_compat(kp->i_flags) ||
10365832c4a7SAlexander Lobakin !ip_tunnel_flags_is_be16_compat(kp->o_flags))
10375832c4a7SAlexander Lobakin return false;
10385832c4a7SAlexander Lobakin
10395a66cda5SAlexander Lobakin memset(&p, 0, sizeof(p));
10405a66cda5SAlexander Lobakin
1041117aef12SAlexander Lobakin strscpy(p.name, kp->name);
1042117aef12SAlexander Lobakin p.link = kp->link;
10435832c4a7SAlexander Lobakin p.i_flags = ip_tunnel_flags_to_be16(kp->i_flags);
10445832c4a7SAlexander Lobakin p.o_flags = ip_tunnel_flags_to_be16(kp->o_flags);
1045117aef12SAlexander Lobakin p.i_key = kp->i_key;
1046117aef12SAlexander Lobakin p.o_key = kp->o_key;
1047117aef12SAlexander Lobakin memcpy(&p.iph, &kp->iph, min(sizeof(p.iph), sizeof(kp->iph)));
1048117aef12SAlexander Lobakin
1049117aef12SAlexander Lobakin return !copy_to_user(data, &p, sizeof(p));
1050117aef12SAlexander Lobakin }
1051117aef12SAlexander Lobakin EXPORT_SYMBOL_GPL(ip_tunnel_parm_to_user);
1052117aef12SAlexander Lobakin
ip_tunnel_siocdevprivate(struct net_device * dev,struct ifreq * ifr,void __user * data,int cmd)10533e7a1c7cSArnd Bergmann int ip_tunnel_siocdevprivate(struct net_device *dev, struct ifreq *ifr,
10543e7a1c7cSArnd Bergmann void __user *data, int cmd)
1055607259a6SChristoph Hellwig {
1056117aef12SAlexander Lobakin struct ip_tunnel_parm_kern p;
1057607259a6SChristoph Hellwig int err;
1058607259a6SChristoph Hellwig
1059117aef12SAlexander Lobakin if (!ip_tunnel_parm_from_user(&p, data))
1060607259a6SChristoph Hellwig return -EFAULT;
1061607259a6SChristoph Hellwig err = dev->netdev_ops->ndo_tunnel_ctl(dev, &p, cmd);
1062117aef12SAlexander Lobakin if (!err && !ip_tunnel_parm_to_user(data, &p))
1063607259a6SChristoph Hellwig return -EFAULT;
1064607259a6SChristoph Hellwig return err;
1065607259a6SChristoph Hellwig }
10663e7a1c7cSArnd Bergmann EXPORT_SYMBOL_GPL(ip_tunnel_siocdevprivate);
1067c5441932SPravin B Shelar
__ip_tunnel_change_mtu(struct net_device * dev,int new_mtu,bool strict)10687e059158SDavid Wragg int __ip_tunnel_change_mtu(struct net_device *dev, int new_mtu, bool strict)
1069c5441932SPravin B Shelar {
1070c5441932SPravin B Shelar struct ip_tunnel *tunnel = netdev_priv(dev);
1071c5441932SPravin B Shelar int t_hlen = tunnel->hlen + sizeof(struct iphdr);
107228e104d0SVadim Fedorenko int max_mtu = IP_MAX_MTU - t_hlen;
1073c5441932SPravin B Shelar
10749992a078SHangbin Liu if (dev->type == ARPHRD_ETHER)
10759992a078SHangbin Liu max_mtu -= dev->hard_header_len;
10769992a078SHangbin Liu
1077b96f9afeSJarod Wilson if (new_mtu < ETH_MIN_MTU)
1078c5441932SPravin B Shelar return -EINVAL;
10797e059158SDavid Wragg
10807e059158SDavid Wragg if (new_mtu > max_mtu) {
10817e059158SDavid Wragg if (strict)
10827e059158SDavid Wragg return -EINVAL;
10837e059158SDavid Wragg
10847e059158SDavid Wragg new_mtu = max_mtu;
10857e059158SDavid Wragg }
10867e059158SDavid Wragg
10871eb2cdedSEric Dumazet WRITE_ONCE(dev->mtu, new_mtu);
1088c5441932SPravin B Shelar return 0;
1089c5441932SPravin B Shelar }
10907e059158SDavid Wragg EXPORT_SYMBOL_GPL(__ip_tunnel_change_mtu);
10917e059158SDavid Wragg
ip_tunnel_change_mtu(struct net_device * dev,int new_mtu)10927e059158SDavid Wragg int ip_tunnel_change_mtu(struct net_device *dev, int new_mtu)
10937e059158SDavid Wragg {
10947e059158SDavid Wragg return __ip_tunnel_change_mtu(dev, new_mtu, true);
10957e059158SDavid Wragg }
1096c5441932SPravin B Shelar EXPORT_SYMBOL_GPL(ip_tunnel_change_mtu);
1097c5441932SPravin B Shelar
ip_tunnel_dev_free(struct net_device * dev)1098c5441932SPravin B Shelar static void ip_tunnel_dev_free(struct net_device *dev)
1099c5441932SPravin B Shelar {
1100c5441932SPravin B Shelar struct ip_tunnel *tunnel = netdev_priv(dev);
1101c5441932SPravin B Shelar
1102c5441932SPravin B Shelar gro_cells_destroy(&tunnel->gro_cells);
1103e09acddfSPaolo Abeni dst_cache_destroy(&tunnel->dst_cache);
1104c5441932SPravin B Shelar }
1105c5441932SPravin B Shelar
ip_tunnel_dellink(struct net_device * dev,struct list_head * head)1106c5441932SPravin B Shelar void ip_tunnel_dellink(struct net_device *dev, struct list_head *head)
1107c5441932SPravin B Shelar {
1108c5441932SPravin B Shelar struct ip_tunnel *tunnel = netdev_priv(dev);
1109c5441932SPravin B Shelar struct ip_tunnel_net *itn;
1110c5441932SPravin B Shelar
11116c742e71SNicolas Dichtel itn = net_generic(tunnel->net, tunnel->ip_tnl_net_id);
1112c5441932SPravin B Shelar
1113c5441932SPravin B Shelar if (itn->fb_tunnel_dev != dev) {
11142e15ea39SPravin B Shelar ip_tunnel_del(itn, netdev_priv(dev));
1115c5441932SPravin B Shelar unregister_netdevice_queue(dev, head);
1116c5441932SPravin B Shelar }
1117c5441932SPravin B Shelar }
1118c5441932SPravin B Shelar EXPORT_SYMBOL_GPL(ip_tunnel_dellink);
1119c5441932SPravin B Shelar
ip_tunnel_get_link_net(const struct net_device * dev)11201728d4faSNicolas Dichtel struct net *ip_tunnel_get_link_net(const struct net_device *dev)
11211728d4faSNicolas Dichtel {
11221728d4faSNicolas Dichtel struct ip_tunnel *tunnel = netdev_priv(dev);
11231728d4faSNicolas Dichtel
11249cf621bdSEric Dumazet return READ_ONCE(tunnel->net);
11251728d4faSNicolas Dichtel }
11261728d4faSNicolas Dichtel EXPORT_SYMBOL(ip_tunnel_get_link_net);
11271728d4faSNicolas Dichtel
ip_tunnel_get_iflink(const struct net_device * dev)11281e99584bSNicolas Dichtel int ip_tunnel_get_iflink(const struct net_device *dev)
11291e99584bSNicolas Dichtel {
1130f694eee9SEric Dumazet const struct ip_tunnel *tunnel = netdev_priv(dev);
11311e99584bSNicolas Dichtel
1132f694eee9SEric Dumazet return READ_ONCE(tunnel->parms.link);
11331e99584bSNicolas Dichtel }
11341e99584bSNicolas Dichtel EXPORT_SYMBOL(ip_tunnel_get_iflink);
11351e99584bSNicolas Dichtel
ip_tunnel_init_net(struct net * net,unsigned int ip_tnl_net_id,struct rtnl_link_ops * ops,char * devname)1136c7d03a00SAlexey Dobriyan int ip_tunnel_init_net(struct net *net, unsigned int ip_tnl_net_id,
1137c5441932SPravin B Shelar struct rtnl_link_ops *ops, char *devname)
1138c5441932SPravin B Shelar {
1139c5441932SPravin B Shelar struct ip_tunnel_net *itn = net_generic(net, ip_tnl_net_id);
1140117aef12SAlexander Lobakin struct ip_tunnel_parm_kern parms;
11416261d983Sstephen hemminger unsigned int i;
1142c5441932SPravin B Shelar
114379134e6cSEric Dumazet itn->rtnl_link_ops = ops;
11446261d983Sstephen hemminger for (i = 0; i < IP_TNL_HASH_SIZE; i++)
11456261d983Sstephen hemminger INIT_HLIST_HEAD(&itn->tunnels[i]);
1146c5441932SPravin B Shelar
114779134e6cSEric Dumazet if (!ops || !net_has_fallback_tunnels(net)) {
114879134e6cSEric Dumazet struct ip_tunnel_net *it_init_net;
114979134e6cSEric Dumazet
115079134e6cSEric Dumazet it_init_net = net_generic(&init_net, ip_tnl_net_id);
115179134e6cSEric Dumazet itn->type = it_init_net->type;
1152c5441932SPravin B Shelar itn->fb_tunnel_dev = NULL;
1153c5441932SPravin B Shelar return 0;
1154c5441932SPravin B Shelar }
11556261d983Sstephen hemminger
1156c5441932SPravin B Shelar memset(&parms, 0, sizeof(parms));
1157c5441932SPravin B Shelar if (devname)
1158512b2dc4SXueBing Chen strscpy(parms.name, devname, IFNAMSIZ);
1159c5441932SPravin B Shelar
1160c5441932SPravin B Shelar rtnl_lock();
1161c5441932SPravin B Shelar itn->fb_tunnel_dev = __ip_tunnel_create(net, ops, &parms);
1162ea857f28SDan Carpenter /* FB netdevice is special: we have one, and only one per netns.
1163ea857f28SDan Carpenter * Allowing to move it to another netns is clearly unsafe.
1164ea857f28SDan Carpenter */
116567013282SSteffen Klassert if (!IS_ERR(itn->fb_tunnel_dev)) {
11660c493da8SNicolas Dichtel itn->fb_tunnel_dev->netns_immutable = true;
116778ff4be4SSteffen Klassert itn->fb_tunnel_dev->mtu = ip_tunnel_bind_dev(itn->fb_tunnel_dev);
116867013282SSteffen Klassert ip_tunnel_add(itn, netdev_priv(itn->fb_tunnel_dev));
116979134e6cSEric Dumazet itn->type = itn->fb_tunnel_dev->type;
117067013282SSteffen Klassert }
1171b4de77adSDan Carpenter rtnl_unlock();
1172c5441932SPravin B Shelar
117327d79f3bSSachin Kamat return PTR_ERR_OR_ZERO(itn->fb_tunnel_dev);
1174c5441932SPravin B Shelar }
1175c5441932SPravin B Shelar EXPORT_SYMBOL_GPL(ip_tunnel_init_net);
1176c5441932SPravin B Shelar
ip_tunnel_delete_net(struct net * net,unsigned int id,struct rtnl_link_ops * ops,struct list_head * head)1177a967e01eSKuniyuki Iwashima void ip_tunnel_delete_net(struct net *net, unsigned int id,
1178a967e01eSKuniyuki Iwashima struct rtnl_link_ops *ops,
1179a967e01eSKuniyuki Iwashima struct list_head *head)
1180c5441932SPravin B Shelar {
1181a967e01eSKuniyuki Iwashima struct ip_tunnel_net *itn = net_generic(net, id);
11826c742e71SNicolas Dichtel struct net_device *dev, *aux;
1183c5441932SPravin B Shelar int h;
1184c5441932SPravin B Shelar
1185a967e01eSKuniyuki Iwashima ASSERT_RTNL_NET(net);
1186a967e01eSKuniyuki Iwashima
11876c742e71SNicolas Dichtel for_each_netdev_safe(net, dev, aux)
11886c742e71SNicolas Dichtel if (dev->rtnl_link_ops == ops)
11896c742e71SNicolas Dichtel unregister_netdevice_queue(dev, head);
11906c742e71SNicolas Dichtel
1191c5441932SPravin B Shelar for (h = 0; h < IP_TNL_HASH_SIZE; h++) {
1192c5441932SPravin B Shelar struct ip_tunnel *t;
1193c5441932SPravin B Shelar struct hlist_node *n;
1194c5441932SPravin B Shelar struct hlist_head *thead = &itn->tunnels[h];
1195c5441932SPravin B Shelar
1196c5441932SPravin B Shelar hlist_for_each_entry_safe(t, n, thead, hash_node)
11976c742e71SNicolas Dichtel /* If dev is in the same netns, it has already
11986c742e71SNicolas Dichtel * been added to the list by the previous loop.
11996c742e71SNicolas Dichtel */
12006c742e71SNicolas Dichtel if (!net_eq(dev_net(t->dev), net))
1201c5441932SPravin B Shelar unregister_netdevice_queue(t->dev, head);
1202c5441932SPravin B Shelar }
1203c5441932SPravin B Shelar }
1204a967e01eSKuniyuki Iwashima EXPORT_SYMBOL_GPL(ip_tunnel_delete_net);
1205c5441932SPravin B Shelar
ip_tunnel_newlink(struct net * net,struct net_device * dev,struct nlattr * tb[],struct ip_tunnel_parm_kern * p,__u32 fwmark)1206eacb1160SXiao Liang int ip_tunnel_newlink(struct net *net, struct net_device *dev,
1207eacb1160SXiao Liang struct nlattr *tb[], struct ip_tunnel_parm_kern *p,
1208eacb1160SXiao Liang __u32 fwmark)
1209c5441932SPravin B Shelar {
1210c5441932SPravin B Shelar struct ip_tunnel *nt;
1211c5441932SPravin B Shelar struct ip_tunnel_net *itn;
1212c5441932SPravin B Shelar int mtu;
1213c5441932SPravin B Shelar int err;
1214c5441932SPravin B Shelar
1215c5441932SPravin B Shelar nt = netdev_priv(dev);
1216c5441932SPravin B Shelar itn = net_generic(net, nt->ip_tnl_net_id);
1217c5441932SPravin B Shelar
12182e15ea39SPravin B Shelar if (nt->collect_md) {
12192e15ea39SPravin B Shelar if (rtnl_dereference(itn->collect_md_tun))
12202e15ea39SPravin B Shelar return -EEXIST;
12212e15ea39SPravin B Shelar } else {
1222c5441932SPravin B Shelar if (ip_tunnel_find(itn, p, dev->type))
1223c5441932SPravin B Shelar return -EEXIST;
12242e15ea39SPravin B Shelar }
1225c5441932SPravin B Shelar
12265e6700b3SNicolas Dichtel nt->net = net;
1227c5441932SPravin B Shelar nt->parms = *p;
12289830ad4cSCraig Gallek nt->fwmark = fwmark;
1229c5441932SPravin B Shelar err = register_netdevice(dev);
1230c5441932SPravin B Shelar if (err)
1231f6cc9c05SPetr Machata goto err_register_netdevice;
1232c5441932SPravin B Shelar
1233c5441932SPravin B Shelar if (dev->type == ARPHRD_ETHER && !tb[IFLA_ADDRESS])
1234c5441932SPravin B Shelar eth_hw_addr_random(dev);
1235c5441932SPravin B Shelar
1236c5441932SPravin B Shelar mtu = ip_tunnel_bind_dev(dev);
123724fc7979SStefano Brivio if (tb[IFLA_MTU]) {
123828e104d0SVadim Fedorenko unsigned int max = IP_MAX_MTU - (nt->hlen + sizeof(struct iphdr));
123924fc7979SStefano Brivio
12409992a078SHangbin Liu if (dev->type == ARPHRD_ETHER)
12419992a078SHangbin Liu max -= dev->hard_header_len;
12429992a078SHangbin Liu
124328e104d0SVadim Fedorenko mtu = clamp(dev->mtu, (unsigned int)ETH_MIN_MTU, max);
12445568cdc3SDavid S. Miller }
12455568cdc3SDavid S. Miller
1246f6cc9c05SPetr Machata err = dev_set_mtu(dev, mtu);
1247f6cc9c05SPetr Machata if (err)
1248f6cc9c05SPetr Machata goto err_dev_set_mtu;
1249c5441932SPravin B Shelar
1250c5441932SPravin B Shelar ip_tunnel_add(itn, nt);
1251f6cc9c05SPetr Machata return 0;
1252f6cc9c05SPetr Machata
1253f6cc9c05SPetr Machata err_dev_set_mtu:
1254f6cc9c05SPetr Machata unregister_netdevice(dev);
1255f6cc9c05SPetr Machata err_register_netdevice:
1256c5441932SPravin B Shelar return err;
1257c5441932SPravin B Shelar }
1258c5441932SPravin B Shelar EXPORT_SYMBOL_GPL(ip_tunnel_newlink);
1259c5441932SPravin B Shelar
ip_tunnel_changelink(struct net_device * dev,struct nlattr * tb[],struct ip_tunnel_parm_kern * p,__u32 fwmark)1260c5441932SPravin B Shelar int ip_tunnel_changelink(struct net_device *dev, struct nlattr *tb[],
1261117aef12SAlexander Lobakin struct ip_tunnel_parm_kern *p, __u32 fwmark)
1262c5441932SPravin B Shelar {
12636c742e71SNicolas Dichtel struct ip_tunnel *t;
1264c5441932SPravin B Shelar struct ip_tunnel *tunnel = netdev_priv(dev);
12656c742e71SNicolas Dichtel struct net *net = tunnel->net;
1266c5441932SPravin B Shelar struct ip_tunnel_net *itn = net_generic(net, tunnel->ip_tnl_net_id);
1267c5441932SPravin B Shelar
1268c5441932SPravin B Shelar if (dev == itn->fb_tunnel_dev)
1269c5441932SPravin B Shelar return -EINVAL;
1270c5441932SPravin B Shelar
1271c5441932SPravin B Shelar t = ip_tunnel_find(itn, p, dev->type);
1272c5441932SPravin B Shelar
1273c5441932SPravin B Shelar if (t) {
1274c5441932SPravin B Shelar if (t->dev != dev)
1275c5441932SPravin B Shelar return -EEXIST;
1276c5441932SPravin B Shelar } else {
12776c742e71SNicolas Dichtel t = tunnel;
1278c5441932SPravin B Shelar
1279c5441932SPravin B Shelar if (dev->type != ARPHRD_ETHER) {
1280c5441932SPravin B Shelar unsigned int nflags = 0;
1281c5441932SPravin B Shelar
1282c5441932SPravin B Shelar if (ipv4_is_multicast(p->iph.daddr))
1283c5441932SPravin B Shelar nflags = IFF_BROADCAST;
1284c5441932SPravin B Shelar else if (p->iph.daddr)
1285c5441932SPravin B Shelar nflags = IFF_POINTOPOINT;
1286c5441932SPravin B Shelar
1287c5441932SPravin B Shelar if ((dev->flags ^ nflags) &
1288c5441932SPravin B Shelar (IFF_POINTOPOINT | IFF_BROADCAST))
1289c5441932SPravin B Shelar return -EINVAL;
1290c5441932SPravin B Shelar }
1291c5441932SPravin B Shelar }
1292c5441932SPravin B Shelar
12939830ad4cSCraig Gallek ip_tunnel_update(itn, t, dev, p, !tb[IFLA_MTU], fwmark);
1294c5441932SPravin B Shelar return 0;
1295c5441932SPravin B Shelar }
1296c5441932SPravin B Shelar EXPORT_SYMBOL_GPL(ip_tunnel_changelink);
1297c5441932SPravin B Shelar
ip_tunnel_init(struct net_device * dev)1298c5441932SPravin B Shelar int ip_tunnel_init(struct net_device *dev)
1299c5441932SPravin B Shelar {
1300c5441932SPravin B Shelar struct ip_tunnel *tunnel = netdev_priv(dev);
1301c5441932SPravin B Shelar struct iphdr *iph = &tunnel->parms.iph;
13021c213bd2SWANG Cong int err;
1303c5441932SPravin B Shelar
1304cf124db5SDavid S. Miller dev->needs_free_netdev = true;
1305cf124db5SDavid S. Miller dev->priv_destructor = ip_tunnel_dev_free;
130645403b12SBreno Leitao dev->pcpu_stat_type = NETDEV_PCPU_STAT_TSTATS;
1307c5441932SPravin B Shelar
1308e09acddfSPaolo Abeni err = dst_cache_init(&tunnel->dst_cache, GFP_KERNEL);
130945403b12SBreno Leitao if (err)
1310e09acddfSPaolo Abeni return err;
13119a4aa9afSTom Herbert
1312c5441932SPravin B Shelar err = gro_cells_init(&tunnel->gro_cells, dev);
1313c5441932SPravin B Shelar if (err) {
1314e09acddfSPaolo Abeni dst_cache_destroy(&tunnel->dst_cache);
1315c5441932SPravin B Shelar return err;
1316c5441932SPravin B Shelar }
1317c5441932SPravin B Shelar
1318c5441932SPravin B Shelar tunnel->dev = dev;
131982183b03SHongbo Li strscpy(tunnel->parms.name, dev->name);
1320c5441932SPravin B Shelar iph->version = 4;
1321c5441932SPravin B Shelar iph->ihl = 5;
1322c5441932SPravin B Shelar
1323d0f41851SWilliam Dauchy if (tunnel->collect_md)
13242e15ea39SPravin B Shelar netif_keep_dst(dev);
13250bef5120SEric Dumazet netdev_lockdep_set_classes(dev);
1326c5441932SPravin B Shelar return 0;
1327c5441932SPravin B Shelar }
1328c5441932SPravin B Shelar EXPORT_SYMBOL_GPL(ip_tunnel_init);
1329c5441932SPravin B Shelar
ip_tunnel_uninit(struct net_device * dev)1330c5441932SPravin B Shelar void ip_tunnel_uninit(struct net_device *dev)
1331c5441932SPravin B Shelar {
1332c5441932SPravin B Shelar struct ip_tunnel *tunnel = netdev_priv(dev);
13336c742e71SNicolas Dichtel struct net *net = tunnel->net;
1334c5441932SPravin B Shelar struct ip_tunnel_net *itn;
1335c5441932SPravin B Shelar
1336c5441932SPravin B Shelar itn = net_generic(net, tunnel->ip_tnl_net_id);
13372e15ea39SPravin B Shelar ip_tunnel_del(itn, netdev_priv(dev));
1338ba61539cSTaehee Yoo if (itn->fb_tunnel_dev == dev)
1339ba61539cSTaehee Yoo WRITE_ONCE(itn->fb_tunnel_dev, NULL);
13407d442fabSTom Herbert
1341e09acddfSPaolo Abeni dst_cache_reset(&tunnel->dst_cache);
1342c5441932SPravin B Shelar }
1343c5441932SPravin B Shelar EXPORT_SYMBOL_GPL(ip_tunnel_uninit);
1344c5441932SPravin B Shelar
1345c5441932SPravin B Shelar /* Do least required initialization, rest of init is done in tunnel_init call */
ip_tunnel_setup(struct net_device * dev,unsigned int net_id)1346c7d03a00SAlexey Dobriyan void ip_tunnel_setup(struct net_device *dev, unsigned int net_id)
1347c5441932SPravin B Shelar {
1348c5441932SPravin B Shelar struct ip_tunnel *tunnel = netdev_priv(dev);
1349c5441932SPravin B Shelar tunnel->ip_tnl_net_id = net_id;
1350c5441932SPravin B Shelar }
1351c5441932SPravin B Shelar EXPORT_SYMBOL_GPL(ip_tunnel_setup);
1352c5441932SPravin B Shelar
1353b058a5d2SBreno Leitao MODULE_DESCRIPTION("IPv4 tunnel implementation library");
1354c5441932SPravin B Shelar MODULE_LICENSE("GPL");
1355