Blame view
net/ipv4/ip_tunnel.c
29 KB
c54419321 GRE: Refactor GRE... |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
/* * Copyright (c) 2013 Nicira, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public * License as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/capability.h> #include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> #include <linux/slab.h> #include <linux/uaccess.h> #include <linux/skbuff.h> #include <linux/netdevice.h> #include <linux/in.h> #include <linux/tcp.h> #include <linux/udp.h> #include <linux/if_arp.h> |
c54419321 GRE: Refactor GRE... |
33 34 35 36 37 38 39 40 41 |
#include <linux/init.h> #include <linux/in6.h> #include <linux/inetdevice.h> #include <linux/igmp.h> #include <linux/netfilter_ipv4.h> #include <linux/etherdevice.h> #include <linux/if_ether.h> #include <linux/if_vlan.h> #include <linux/rculist.h> |
27d79f3b1 net: ipv4: Use PT... |
42 |
#include <linux/err.h> |
c54419321 GRE: Refactor GRE... |
43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
#include <net/sock.h> #include <net/ip.h> #include <net/icmp.h> #include <net/protocol.h> #include <net/ip_tunnels.h> #include <net/arp.h> #include <net/checksum.h> #include <net/dsfield.h> #include <net/inet_ecn.h> #include <net/xfrm.h> #include <net/net_namespace.h> #include <net/netns/generic.h> #include <net/rtnetlink.h> |
563284865 net: Changes to i... |
57 |
#include <net/udp.h> |
cfc7381b3 ip_tunnel: add co... |
58 |
#include <net/dst_metadata.h> |
63487babf net: Move fou_bui... |
59 |
|
c54419321 GRE: Refactor GRE... |
60 61 62 63 64 |
#if IS_ENABLED(CONFIG_IPV6) #include <net/ipv6.h> #include <net/ip6_fib.h> #include <net/ip6_route.h> #endif |
967680e02 ipv4: remove the ... |
65 |
static unsigned int ip_tunnel_hash(__be32 key, __be32 remote) |
c54419321 GRE: Refactor GRE... |
66 67 68 69 |
{ return hash_32((__force u32)key ^ (__force u32)remote, IP_TNL_HASH_BITS); } |
c54419321 GRE: Refactor GRE... |
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
static bool ip_tunnel_key_match(const struct ip_tunnel_parm *p, __be16 flags, __be32 key) { if (p->i_flags & TUNNEL_KEY) { if (flags & TUNNEL_KEY) return key == p->i_key; else /* key expected, none present */ return false; } else return !(flags & TUNNEL_KEY); } /* Fallback tunnel: no source, no destination, no key, no options Tunnel hash table: We require exact key match i.e. if a key is present in packet it will match only tunnel with the same key; if it is not present, it will match only keyless tunnel. All keysless packets, if not matched configured keyless tunnels will match fallback tunnel. Given src, dst and key, find appropriate for input tunnel. */ struct ip_tunnel *ip_tunnel_lookup(struct ip_tunnel_net *itn, int link, __be16 flags, __be32 remote, __be32 local, __be32 key) { unsigned int hash; struct ip_tunnel *t, *cand = NULL; struct hlist_head *head; |
967680e02 ipv4: remove the ... |
102 |
hash = ip_tunnel_hash(key, remote); |
c54419321 GRE: Refactor GRE... |
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
head = &itn->tunnels[hash]; hlist_for_each_entry_rcu(t, head, hash_node) { if (local != t->parms.iph.saddr || remote != t->parms.iph.daddr || !(t->dev->flags & IFF_UP)) continue; if (!ip_tunnel_key_match(&t->parms, flags, key)) continue; if (t->parms.link == link) return t; else cand = t; } hlist_for_each_entry_rcu(t, head, hash_node) { if (remote != t->parms.iph.daddr || |
e0056593b ip_tunnel: fix ip... |
122 |
t->parms.iph.saddr != 0 || |
c54419321 GRE: Refactor GRE... |
123 124 125 126 127 128 129 130 131 132 133 |
!(t->dev->flags & IFF_UP)) continue; if (!ip_tunnel_key_match(&t->parms, flags, key)) continue; if (t->parms.link == link) return t; else if (!cand) cand = t; } |
967680e02 ipv4: remove the ... |
134 |
hash = ip_tunnel_hash(key, 0); |
c54419321 GRE: Refactor GRE... |
135 136 137 |
head = &itn->tunnels[hash]; hlist_for_each_entry_rcu(t, head, hash_node) { |
e0056593b ip_tunnel: fix ip... |
138 139 140 141 142 |
if ((local != t->parms.iph.saddr || t->parms.iph.daddr != 0) && (local != t->parms.iph.daddr || !ipv4_is_multicast(local))) continue; if (!(t->dev->flags & IFF_UP)) |
c54419321 GRE: Refactor GRE... |
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 |
continue; if (!ip_tunnel_key_match(&t->parms, flags, key)) continue; if (t->parms.link == link) return t; else if (!cand) cand = t; } if (flags & TUNNEL_NO_KEY) goto skip_key_lookup; hlist_for_each_entry_rcu(t, head, hash_node) { if (t->parms.i_key != key || |
e0056593b ip_tunnel: fix ip... |
159 160 |
t->parms.iph.saddr != 0 || t->parms.iph.daddr != 0 || |
c54419321 GRE: Refactor GRE... |
161 162 163 164 165 166 167 168 169 170 171 172 |
!(t->dev->flags & IFF_UP)) continue; if (t->parms.link == link) return t; else if (!cand) cand = t; } skip_key_lookup: if (cand) return cand; |
2e15ea390 ip_gre: Add suppo... |
173 |
t = rcu_dereference(itn->collect_md_tun); |
833a8b405 ip_tunnel: fix ip... |
174 |
if (t && t->dev->flags & IFF_UP) |
2e15ea390 ip_gre: Add suppo... |
175 |
return t; |
c54419321 GRE: Refactor GRE... |
176 177 |
if (itn->fb_tunnel_dev && itn->fb_tunnel_dev->flags & IFF_UP) return netdev_priv(itn->fb_tunnel_dev); |
c54419321 GRE: Refactor GRE... |
178 179 180 181 182 183 184 185 186 |
return NULL; } EXPORT_SYMBOL_GPL(ip_tunnel_lookup); static struct hlist_head *ip_bucket(struct ip_tunnel_net *itn, struct ip_tunnel_parm *parms) { unsigned int h; __be32 remote; |
6d608f06e ip_tunnel: Make v... |
187 |
__be32 i_key = parms->i_key; |
c54419321 GRE: Refactor GRE... |
188 189 190 191 192 |
if (parms->iph.daddr && !ipv4_is_multicast(parms->iph.daddr)) remote = parms->iph.daddr; else remote = 0; |
6d608f06e ip_tunnel: Make v... |
193 194 195 196 |
if (!(parms->i_flags & TUNNEL_KEY) && (parms->i_flags & VTI_ISVTI)) i_key = 0; h = ip_tunnel_hash(i_key, remote); |
c54419321 GRE: Refactor GRE... |
197 198 199 200 201 202 |
return &itn->tunnels[h]; } static void ip_tunnel_add(struct ip_tunnel_net *itn, struct ip_tunnel *t) { struct hlist_head *head = ip_bucket(itn, &t->parms); |
2e15ea390 ip_gre: Add suppo... |
203 204 |
if (t->collect_md) rcu_assign_pointer(itn->collect_md_tun, t); |
c54419321 GRE: Refactor GRE... |
205 206 |
hlist_add_head_rcu(&t->hash_node, head); } |
2e15ea390 ip_gre: Add suppo... |
207 |
static void ip_tunnel_del(struct ip_tunnel_net *itn, struct ip_tunnel *t) |
c54419321 GRE: Refactor GRE... |
208 |
{ |
2e15ea390 ip_gre: Add suppo... |
209 210 |
if (t->collect_md) rcu_assign_pointer(itn->collect_md_tun, NULL); |
c54419321 GRE: Refactor GRE... |
211 212 213 214 215 216 217 218 219 220 |
hlist_del_init_rcu(&t->hash_node); } static struct ip_tunnel *ip_tunnel_find(struct ip_tunnel_net *itn, struct ip_tunnel_parm *parms, int type) { __be32 remote = parms->iph.daddr; __be32 local = parms->iph.saddr; __be32 key = parms->i_key; |
5ce54af1f ip_tunnel: fix i_... |
221 |
__be16 flags = parms->i_flags; |
c54419321 GRE: Refactor GRE... |
222 223 224 225 226 227 228 |
int link = parms->link; struct ip_tunnel *t = NULL; struct hlist_head *head = ip_bucket(itn, parms); hlist_for_each_entry_rcu(t, head, hash_node) { if (local == t->parms.iph.saddr && remote == t->parms.iph.daddr && |
c54419321 GRE: Refactor GRE... |
229 |
link == t->parms.link && |
5ce54af1f ip_tunnel: fix i_... |
230 231 |
type == t->dev->type && ip_tunnel_key_match(&t->parms, flags, key)) |
c54419321 GRE: Refactor GRE... |
232 233 234 235 236 237 238 239 240 241 242 243 244 |
break; } return t; } static struct net_device *__ip_tunnel_create(struct net *net, const struct rtnl_link_ops *ops, struct ip_tunnel_parm *parms) { int err; struct ip_tunnel *tunnel; struct net_device *dev; char name[IFNAMSIZ]; |
6816295fe ip_tunnel: better... |
245 246 247 248 |
err = -E2BIG; if (parms->name[0]) { if (!dev_valid_name(parms->name)) goto failed; |
c54419321 GRE: Refactor GRE... |
249 |
strlcpy(name, parms->name, IFNAMSIZ); |
6816295fe ip_tunnel: better... |
250 251 |
} else { if (strlen(ops->kind) > (IFNAMSIZ - 3)) |
c54419321 GRE: Refactor GRE... |
252 |
goto failed; |
bb1d0ac3e ip_tunnel: Fix na... |
253 254 |
strcpy(name, ops->kind); strcat(name, "%d"); |
c54419321 GRE: Refactor GRE... |
255 256 257 |
} ASSERT_RTNL(); |
c835a6773 net: set name_ass... |
258 |
dev = alloc_netdev(ops->priv_size, name, NET_NAME_UNKNOWN, ops->setup); |
c54419321 GRE: Refactor GRE... |
259 260 261 262 263 264 265 266 267 268 |
if (!dev) { err = -ENOMEM; goto failed; } dev_net_set(dev, net); dev->rtnl_link_ops = ops; tunnel = netdev_priv(dev); tunnel->parms = *parms; |
5e6700b3b sit: add support ... |
269 |
tunnel->net = net; |
c54419321 GRE: Refactor GRE... |
270 271 272 273 274 275 276 277 278 279 280 281 |
err = register_netdevice(dev); if (err) goto failed_free; return dev; failed_free: free_netdev(dev); failed: return ERR_PTR(err); } |
7d442fab0 ipv4: Cache dst i... |
282 283 284 |
static inline void init_tunnel_flow(struct flowi4 *fl4, int proto, __be32 daddr, __be32 saddr, |
9830ad4c6 ip_tunnel: Allow ... |
285 286 |
__be32 key, __u8 tos, int oif, __u32 mark) |
c54419321 GRE: Refactor GRE... |
287 288 289 290 291 292 293 294 |
{ memset(fl4, 0, sizeof(*fl4)); fl4->flowi4_oif = oif; fl4->daddr = daddr; fl4->saddr = saddr; fl4->flowi4_tos = tos; fl4->flowi4_proto = proto; fl4->fl4_gre_key = key; |
9830ad4c6 ip_tunnel: Allow ... |
295 |
fl4->flowi4_mark = mark; |
c54419321 GRE: Refactor GRE... |
296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 |
} static int ip_tunnel_bind_dev(struct net_device *dev) { struct net_device *tdev = NULL; struct ip_tunnel *tunnel = netdev_priv(dev); const struct iphdr *iph; int hlen = LL_MAX_HEADER; int mtu = ETH_DATA_LEN; int t_hlen = tunnel->hlen + sizeof(struct iphdr); iph = &tunnel->parms.iph; /* Guess output device to choose reasonable mtu and needed_headroom */ if (iph->daddr) { struct flowi4 fl4; struct rtable *rt; |
7d442fab0 ipv4: Cache dst i... |
313 314 |
init_tunnel_flow(&fl4, iph->protocol, iph->daddr, iph->saddr, tunnel->parms.o_key, |
9830ad4c6 ip_tunnel: Allow ... |
315 316 |
RT_TOS(iph->tos), tunnel->parms.link, tunnel->fwmark); |
7d442fab0 ipv4: Cache dst i... |
317 |
rt = ip_route_output_key(tunnel->net, &fl4); |
c54419321 GRE: Refactor GRE... |
318 319 320 321 322 323 |
if (!IS_ERR(rt)) { tdev = rt->dst.dev; ip_rt_put(rt); } if (dev->type != ARPHRD_ETHER) dev->flags |= IFF_POINTOPOINT; |
f27337e16 ip_tunnel: fix pr... |
324 325 |
dst_cache_reset(&tunnel->dst_cache); |
c54419321 GRE: Refactor GRE... |
326 327 328 |
} if (!tdev && tunnel->parms.link) |
6c742e714 ipip: add x-netns... |
329 |
tdev = __dev_get_by_index(tunnel->net, tunnel->parms.link); |
c54419321 GRE: Refactor GRE... |
330 331 332 333 334 |
if (tdev) { hlen = tdev->hard_header_len + tdev->needed_headroom; mtu = tdev->mtu; } |
c54419321 GRE: Refactor GRE... |
335 336 337 |
dev->needed_headroom = t_hlen + hlen; mtu -= (dev->hard_header_len + t_hlen); |
57dfc3d10 ipv4: igmp: guard... |
338 339 |
if (mtu < IPV4_MIN_MTU) mtu = IPV4_MIN_MTU; |
c54419321 GRE: Refactor GRE... |
340 341 342 343 344 345 346 347 |
return mtu; } static struct ip_tunnel *ip_tunnel_create(struct net *net, struct ip_tunnel_net *itn, struct ip_tunnel_parm *parms) { |
4929fd8cb ip_tunnel: delete... |
348 |
struct ip_tunnel *nt; |
c54419321 GRE: Refactor GRE... |
349 |
struct net_device *dev; |
b96f9afee ipv4/6: use core ... |
350 |
int t_hlen; |
c54419321 GRE: Refactor GRE... |
351 352 |
BUG_ON(!itn->fb_tunnel_dev); |
c54419321 GRE: Refactor GRE... |
353 354 |
dev = __ip_tunnel_create(net, itn->fb_tunnel_dev->rtnl_link_ops, parms); if (IS_ERR(dev)) |
6dd3c9ec2 ip_tunnel: return... |
355 |
return ERR_CAST(dev); |
c54419321 GRE: Refactor GRE... |
356 357 358 359 |
dev->mtu = ip_tunnel_bind_dev(dev); nt = netdev_priv(dev); |
b96f9afee ipv4/6: use core ... |
360 361 362 |
t_hlen = nt->hlen + sizeof(struct iphdr); dev->min_mtu = ETH_MIN_MTU; dev->max_mtu = 0xFFF8 - dev->hard_header_len - t_hlen; |
c54419321 GRE: Refactor GRE... |
363 364 365 366 367 |
ip_tunnel_add(itn, nt); return nt; } int ip_tunnel_rcv(struct ip_tunnel *tunnel, struct sk_buff *skb, |
2e15ea390 ip_gre: Add suppo... |
368 369 |
const struct tnl_ptk_info *tpi, struct metadata_dst *tun_dst, bool log_ecn_error) |
c54419321 GRE: Refactor GRE... |
370 |
{ |
8f84985fe net: unify the pc... |
371 |
struct pcpu_sw_netstats *tstats; |
c54419321 GRE: Refactor GRE... |
372 373 |
const struct iphdr *iph = ip_hdr(skb); int err; |
c54419321 GRE: Refactor GRE... |
374 375 |
#ifdef CONFIG_NET_IPGRE_BROADCAST if (ipv4_is_multicast(iph->daddr)) { |
c54419321 GRE: Refactor GRE... |
376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 |
tunnel->dev->stats.multicast++; skb->pkt_type = PACKET_BROADCAST; } #endif if ((!(tpi->flags&TUNNEL_CSUM) && (tunnel->parms.i_flags&TUNNEL_CSUM)) || ((tpi->flags&TUNNEL_CSUM) && !(tunnel->parms.i_flags&TUNNEL_CSUM))) { tunnel->dev->stats.rx_crc_errors++; tunnel->dev->stats.rx_errors++; goto drop; } if (tunnel->parms.i_flags&TUNNEL_SEQ) { if (!(tpi->flags&TUNNEL_SEQ) || (tunnel->i_seqno && (s32)(ntohl(tpi->seq) - tunnel->i_seqno) < 0)) { tunnel->dev->stats.rx_fifo_errors++; tunnel->dev->stats.rx_errors++; goto drop; } tunnel->i_seqno = ntohl(tpi->seq) + 1; } |
e96f2e7c4 ip_tunnel: Set ne... |
397 |
skb_reset_network_header(skb); |
c54419321 GRE: Refactor GRE... |
398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 |
err = IP_ECN_decapsulate(iph, skb); if (unlikely(err)) { if (log_ecn_error) net_info_ratelimited("non-ECT from %pI4 with TOS=%#x ", &iph->saddr, iph->tos); if (err > 1) { ++tunnel->dev->stats.rx_frame_errors; ++tunnel->dev->stats.rx_errors; goto drop; } } tstats = this_cpu_ptr(tunnel->dev->tstats); u64_stats_update_begin(&tstats->syncp); tstats->rx_packets++; tstats->rx_bytes += skb->len; u64_stats_update_end(&tstats->syncp); |
81b9eab5e core/dev: do not ... |
416 |
skb_scrub_packet(skb, !net_eq(tunnel->net, dev_net(tunnel->dev))); |
3d7b46cd2 ip_tunnel: push g... |
417 418 419 420 421 422 |
if (tunnel->dev->type == ARPHRD_ETHER) { skb->protocol = eth_type_trans(skb, tunnel->dev); skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN); } else { skb->dev = tunnel->dev; } |
64261f230 dev: move skb_scr... |
423 |
|
2e15ea390 ip_gre: Add suppo... |
424 425 |
if (tun_dst) skb_dst_set(skb, (struct dst_entry *)tun_dst); |
c54419321 GRE: Refactor GRE... |
426 427 428 429 |
gro_cells_receive(&tunnel->gro_cells, skb); return 0; drop: |
469f87e15 ip_tunnel: fix po... |
430 431 |
if (tun_dst) dst_release((struct dst_entry *)tun_dst); |
c54419321 GRE: Refactor GRE... |
432 433 434 435 |
kfree_skb(skb); return 0; } EXPORT_SYMBOL_GPL(ip_tunnel_rcv); |
a8c5f90fb ip_tunnel: Ops re... |
436 437 438 |
int ip_tunnel_encap_add_ops(const struct ip_tunnel_encap_ops *ops, unsigned int num) { |
bb1553c80 ip_tunnel: Add sa... |
439 440 |
if (num >= MAX_IPTUN_ENCAP_OPS) return -ERANGE; |
a8c5f90fb ip_tunnel: Ops re... |
441 442 443 |
return !cmpxchg((const struct ip_tunnel_encap_ops **) &iptun_encaps[num], NULL, ops) ? 0 : -1; |
563284865 net: Changes to i... |
444 |
} |
a8c5f90fb ip_tunnel: Ops re... |
445 446 447 448 449 450 |
EXPORT_SYMBOL(ip_tunnel_encap_add_ops); int ip_tunnel_encap_del_ops(const struct ip_tunnel_encap_ops *ops, unsigned int num) { int ret; |
bb1553c80 ip_tunnel: Add sa... |
451 452 |
if (num >= MAX_IPTUN_ENCAP_OPS) return -ERANGE; |
a8c5f90fb ip_tunnel: Ops re... |
453 454 455 456 457 458 459 460 461 |
ret = (cmpxchg((const struct ip_tunnel_encap_ops **) &iptun_encaps[num], ops, NULL) == ops) ? 0 : -1; synchronize_net(); return ret; } EXPORT_SYMBOL(ip_tunnel_encap_del_ops); |
563284865 net: Changes to i... |
462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 |
int ip_tunnel_encap_setup(struct ip_tunnel *t, struct ip_tunnel_encap *ipencap) { int hlen; memset(&t->encap, 0, sizeof(t->encap)); hlen = ip_encap_hlen(ipencap); if (hlen < 0) return hlen; t->encap.type = ipencap->type; t->encap.sport = ipencap->sport; t->encap.dport = ipencap->dport; t->encap.flags = ipencap->flags; t->encap_hlen = hlen; t->hlen = t->encap_hlen + t->tun_hlen; return 0; } EXPORT_SYMBOL_GPL(ip_tunnel_encap_setup); |
23a3647bc ip_tunnels: Use s... |
485 |
static int tnl_update_pmtu(struct net_device *dev, struct sk_buff *skb, |
fc24f2b20 ip_tunnel: fix ip... |
486 487 |
struct rtable *rt, __be16 df, const struct iphdr *inner_iph) |
23a3647bc ip_tunnels: Use s... |
488 489 |
{ struct ip_tunnel *tunnel = netdev_priv(dev); |
8c91e162e gre: Fix MTU sizi... |
490 |
int pkt_size = skb->len - tunnel->hlen - dev->hard_header_len; |
23a3647bc ip_tunnels: Use s... |
491 492 493 494 495 496 497 |
int mtu; if (df) mtu = dst_mtu(&rt->dst) - dev->hard_header_len - sizeof(struct iphdr) - tunnel->hlen; else mtu = skb_dst(skb) ? dst_mtu(skb_dst(skb)) : dev->mtu; |
6a3c946b2 net: don't call u... |
498 |
skb_dst_update_pmtu(skb, mtu); |
23a3647bc ip_tunnels: Use s... |
499 500 501 |
if (skb->protocol == htons(ETH_P_IP)) { if (!skb_is_gso(skb) && |
fc24f2b20 ip_tunnel: fix ip... |
502 503 |
(inner_iph->frag_off & htons(IP_DF)) && mtu < pkt_size) { |
23a3647bc ip_tunnels: Use s... |
504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 |
memset(IPCB(skb), 0, sizeof(*IPCB(skb))); icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu)); return -E2BIG; } } #if IS_ENABLED(CONFIG_IPV6) else if (skb->protocol == htons(ETH_P_IPV6)) { struct rt6_info *rt6 = (struct rt6_info *)skb_dst(skb); if (rt6 && mtu < dst_mtu(skb_dst(skb)) && mtu >= IPV6_MIN_MTU) { if ((tunnel->parms.iph.daddr && !ipv4_is_multicast(tunnel->parms.iph.daddr)) || rt6->rt6i_dst.plen == 128) { rt6->rt6i_flags |= RTF_MODIFIED; dst_metric_set(skb_dst(skb), RTAX_MTU, mtu); } } if (!skb_is_gso(skb) && mtu >= IPV6_MIN_MTU && mtu < pkt_size) { icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); return -E2BIG; } } #endif return 0; } |
cfc7381b3 ip_tunnel: add co... |
532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 |
void ip_md_tunnel_xmit(struct sk_buff *skb, struct net_device *dev, u8 proto) { struct ip_tunnel *tunnel = netdev_priv(dev); u32 headroom = sizeof(struct iphdr); struct ip_tunnel_info *tun_info; const struct ip_tunnel_key *key; const struct iphdr *inner_iph; struct rtable *rt; struct flowi4 fl4; __be16 df = 0; u8 tos, ttl; tun_info = skb_tunnel_info(skb); if (unlikely(!tun_info || !(tun_info->mode & IP_TUNNEL_INFO_TX) || ip_tunnel_info_af(tun_info) != AF_INET)) goto tx_error; key = &tun_info->key; memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); inner_iph = (const struct iphdr *)skb_inner_network_header(skb); tos = key->tos; if (tos == 1) { if (skb->protocol == htons(ETH_P_IP)) tos = inner_iph->tos; else if (skb->protocol == htons(ETH_P_IPV6)) tos = ipv6_get_dsfield((const struct ipv6hdr *)inner_iph); } init_tunnel_flow(&fl4, proto, key->u.ipv4.dst, key->u.ipv4.src, 0, |
9830ad4c6 ip_tunnel: Allow ... |
559 |
RT_TOS(tos), tunnel->parms.link, tunnel->fwmark); |
cfc7381b3 ip_tunnel: add co... |
560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 |
if (tunnel->encap.type != TUNNEL_ENCAP_NONE) goto tx_error; rt = ip_route_output_key(tunnel->net, &fl4); if (IS_ERR(rt)) { dev->stats.tx_carrier_errors++; goto tx_error; } if (rt->dst.dev == dev) { ip_rt_put(rt); dev->stats.collisions++; goto tx_error; } tos = ip_tunnel_ecn_encap(tos, inner_iph, skb); ttl = key->ttl; if (ttl == 0) { if (skb->protocol == htons(ETH_P_IP)) ttl = inner_iph->ttl; else if (skb->protocol == htons(ETH_P_IPV6)) ttl = ((const struct ipv6hdr *)inner_iph)->hop_limit; else ttl = ip4_dst_hoplimit(&rt->dst); } if (key->tun_flags & TUNNEL_DONT_FRAGMENT) df = htons(IP_DF); else if (skb->protocol == htons(ETH_P_IP)) df = inner_iph->frag_off & htons(IP_DF); headroom += LL_RESERVED_SPACE(rt->dst.dev) + rt->dst.header_len; if (headroom > dev->needed_headroom) dev->needed_headroom = headroom; if (skb_cow_head(skb, dev->needed_headroom)) { ip_rt_put(rt); goto tx_dropped; } |
0f693f199 ip_tunnel: fix se... |
594 595 |
iptunnel_xmit(NULL, rt, skb, fl4.saddr, fl4.daddr, proto, tos, ttl, df, !net_eq(tunnel->net, dev_net(dev))); |
cfc7381b3 ip_tunnel: add co... |
596 597 598 599 600 601 602 603 604 605 |
return; tx_error: dev->stats.tx_errors++; goto kfree; tx_dropped: dev->stats.tx_dropped++; kfree: kfree_skb(skb); } EXPORT_SYMBOL_GPL(ip_md_tunnel_xmit); |
c54419321 GRE: Refactor GRE... |
606 |
void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev, |
563284865 net: Changes to i... |
607 |
const struct iphdr *tnl_params, u8 protocol) |
c54419321 GRE: Refactor GRE... |
608 609 |
{ struct ip_tunnel *tunnel = netdev_priv(dev); |
deb33b68f ip_tunnel: be car... |
610 |
unsigned int inner_nhdr_len = 0; |
c54419321 GRE: Refactor GRE... |
611 |
const struct iphdr *inner_iph; |
c54419321 GRE: Refactor GRE... |
612 613 614 |
struct flowi4 fl4; u8 tos, ttl; __be16 df; |
b045d37bd ip_tunnel: fix pa... |
615 |
struct rtable *rt; /* Route to the other host */ |
c54419321 GRE: Refactor GRE... |
616 617 |
unsigned int max_headroom; /* The extra header space needed */ __be32 dst; |
22fb22eae ipv4: ip_tunnels:... |
618 |
bool connected; |
c54419321 GRE: Refactor GRE... |
619 |
|
deb33b68f ip_tunnel: be car... |
620 621 622 623 624 625 626 |
/* ensure we can access the inner net header, for several users below */ if (skb->protocol == htons(ETH_P_IP)) inner_nhdr_len = sizeof(struct iphdr); else if (skb->protocol == htons(ETH_P_IPV6)) inner_nhdr_len = sizeof(struct ipv6hdr); if (unlikely(!pskb_may_pull(skb, inner_nhdr_len))) goto tx_error; |
c54419321 GRE: Refactor GRE... |
627 |
inner_iph = (const struct iphdr *)skb_inner_network_header(skb); |
22fb22eae ipv4: ip_tunnels:... |
628 |
connected = (tunnel->parms.iph.daddr != 0); |
c54419321 GRE: Refactor GRE... |
629 |
|
5146d1f15 tunnel: Clear IPC... |
630 |
memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); |
c54419321 GRE: Refactor GRE... |
631 632 633 |
dst = tnl_params->daddr; if (dst == 0) { /* NBMA tunnel */ |
51456b291 ipv4: coding styl... |
634 |
if (!skb_dst(skb)) { |
c54419321 GRE: Refactor GRE... |
635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 |
dev->stats.tx_fifo_errors++; goto tx_error; } if (skb->protocol == htons(ETH_P_IP)) { rt = skb_rtable(skb); dst = rt_nexthop(rt, inner_iph->daddr); } #if IS_ENABLED(CONFIG_IPV6) else if (skb->protocol == htons(ETH_P_IPV6)) { const struct in6_addr *addr6; struct neighbour *neigh; bool do_tx_error_icmp; int addr_type; neigh = dst_neigh_lookup(skb_dst(skb), &ipv6_hdr(skb)->daddr); |
51456b291 ipv4: coding styl... |
652 |
if (!neigh) |
c54419321 GRE: Refactor GRE... |
653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 |
goto tx_error; addr6 = (const struct in6_addr *)&neigh->primary_key; addr_type = ipv6_addr_type(addr6); if (addr_type == IPV6_ADDR_ANY) { addr6 = &ipv6_hdr(skb)->daddr; addr_type = ipv6_addr_type(addr6); } if ((addr_type & IPV6_ADDR_COMPATv4) == 0) do_tx_error_icmp = true; else { do_tx_error_icmp = false; dst = addr6->s6_addr32[3]; } neigh_release(neigh); if (do_tx_error_icmp) goto tx_error_icmp; } #endif else goto tx_error; |
7d442fab0 ipv4: Cache dst i... |
676 677 |
connected = false; |
c54419321 GRE: Refactor GRE... |
678 679 680 681 682 |
} tos = tnl_params->tos; if (tos & 0x1) { tos &= ~0x1; |
7d442fab0 ipv4: Cache dst i... |
683 |
if (skb->protocol == htons(ETH_P_IP)) { |
c54419321 GRE: Refactor GRE... |
684 |
tos = inner_iph->tos; |
7d442fab0 ipv4: Cache dst i... |
685 686 |
connected = false; } else if (skb->protocol == htons(ETH_P_IPV6)) { |
c54419321 GRE: Refactor GRE... |
687 |
tos = ipv6_get_dsfield((const struct ipv6hdr *)inner_iph); |
7d442fab0 ipv4: Cache dst i... |
688 689 |
connected = false; } |
c54419321 GRE: Refactor GRE... |
690 |
} |
7d442fab0 ipv4: Cache dst i... |
691 |
init_tunnel_flow(&fl4, protocol, dst, tnl_params->saddr, |
9830ad4c6 ip_tunnel: Allow ... |
692 693 |
tunnel->parms.o_key, RT_TOS(tos), tunnel->parms.link, tunnel->fwmark); |
7d442fab0 ipv4: Cache dst i... |
694 |
|
563284865 net: Changes to i... |
695 696 |
if (ip_tunnel_encap(skb, tunnel, &protocol, &fl4) < 0) goto tx_error; |
e09acddf8 ip_tunnel: replac... |
697 698 |
rt = connected ? dst_cache_get_ip4(&tunnel->dst_cache, &fl4.saddr) : NULL; |
7d442fab0 ipv4: Cache dst i... |
699 700 701 702 703 704 705 706 707 |
if (!rt) { rt = ip_route_output_key(tunnel->net, &fl4); if (IS_ERR(rt)) { dev->stats.tx_carrier_errors++; goto tx_error; } if (connected) |
e09acddf8 ip_tunnel: replac... |
708 709 |
dst_cache_set_ip4(&tunnel->dst_cache, &rt->dst, fl4.saddr); |
c54419321 GRE: Refactor GRE... |
710 |
} |
7d442fab0 ipv4: Cache dst i... |
711 |
|
0e6fbc5b6 ip_tunnels: exten... |
712 |
if (rt->dst.dev == dev) { |
c54419321 GRE: Refactor GRE... |
713 714 715 716 |
ip_rt_put(rt); dev->stats.collisions++; goto tx_error; } |
c54419321 GRE: Refactor GRE... |
717 |
|
fc24f2b20 ip_tunnel: fix ip... |
718 |
if (tnl_update_pmtu(dev, skb, rt, tnl_params->frag_off, inner_iph)) { |
23a3647bc ip_tunnels: Use s... |
719 720 |
ip_rt_put(rt); goto tx_error; |
c54419321 GRE: Refactor GRE... |
721 |
} |
c54419321 GRE: Refactor GRE... |
722 723 724 725 726 727 728 729 730 731 |
if (tunnel->err_count > 0) { if (time_before(jiffies, tunnel->err_time + IPTUNNEL_ERR_TIMEO)) { tunnel->err_count--; dst_link_failure(skb); } else tunnel->err_count = 0; } |
d4a71b155 ip_tunnel: Do not... |
732 |
tos = ip_tunnel_ecn_encap(tos, inner_iph, skb); |
c54419321 GRE: Refactor GRE... |
733 734 735 736 737 738 739 740 741 742 743 |
ttl = tnl_params->ttl; if (ttl == 0) { if (skb->protocol == htons(ETH_P_IP)) ttl = inner_iph->ttl; #if IS_ENABLED(CONFIG_IPV6) else if (skb->protocol == htons(ETH_P_IPV6)) ttl = ((const struct ipv6hdr *)inner_iph)->hop_limit; #endif else ttl = ip4_dst_hoplimit(&rt->dst); } |
23a3647bc ip_tunnels: Use s... |
744 |
df = tnl_params->frag_off; |
22a59be8b net: ipv4: Add ab... |
745 |
if (skb->protocol == htons(ETH_P_IP) && !tunnel->ignore_df) |
23a3647bc ip_tunnels: Use s... |
746 |
df |= (inner_iph->frag_off&htons(IP_DF)); |
0e6fbc5b6 ip_tunnels: exten... |
747 |
max_headroom = LL_RESERVED_SPACE(rt->dst.dev) + sizeof(struct iphdr) |
7371e0221 ip_tunnel: Accoun... |
748 |
+ rt->dst.header_len + ip_encap_hlen(&tunnel->encap); |
3e08f4a72 ip_tunnel: Fix a ... |
749 |
if (max_headroom > dev->needed_headroom) |
c54419321 GRE: Refactor GRE... |
750 |
dev->needed_headroom = max_headroom; |
3e08f4a72 ip_tunnel: Fix a ... |
751 752 |
if (skb_cow_head(skb, dev->needed_headroom)) { |
586d5fc86 ip_tunnel: fix po... |
753 |
ip_rt_put(rt); |
3e08f4a72 ip_tunnel: Fix a ... |
754 |
dev->stats.tx_dropped++; |
3acfa1e73 ipv4: be friend w... |
755 |
kfree_skb(skb); |
3e08f4a72 ip_tunnel: Fix a ... |
756 |
return; |
c54419321 GRE: Refactor GRE... |
757 |
} |
039f50629 ip_tunnel: Move s... |
758 759 |
iptunnel_xmit(NULL, rt, skb, fl4.saddr, fl4.daddr, protocol, tos, ttl, df, !net_eq(tunnel->net, dev_net(dev))); |
c54419321 GRE: Refactor GRE... |
760 761 762 763 764 765 766 767 |
return; #if IS_ENABLED(CONFIG_IPV6) tx_error_icmp: dst_link_failure(skb); #endif tx_error: dev->stats.tx_errors++; |
3acfa1e73 ipv4: be friend w... |
768 |
kfree_skb(skb); |
c54419321 GRE: Refactor GRE... |
769 770 771 772 773 774 775 |
} EXPORT_SYMBOL_GPL(ip_tunnel_xmit); static void ip_tunnel_update(struct ip_tunnel_net *itn, struct ip_tunnel *t, struct net_device *dev, struct ip_tunnel_parm *p, |
9830ad4c6 ip_tunnel: Allow ... |
776 777 |
bool set_mtu, __u32 fwmark) |
c54419321 GRE: Refactor GRE... |
778 |
{ |
2e15ea390 ip_gre: Add suppo... |
779 |
ip_tunnel_del(itn, t); |
c54419321 GRE: Refactor GRE... |
780 781 782 783 784 785 786 787 788 789 790 791 792 |
t->parms.iph.saddr = p->iph.saddr; t->parms.iph.daddr = p->iph.daddr; t->parms.i_key = p->i_key; t->parms.o_key = p->o_key; if (dev->type != ARPHRD_ETHER) { memcpy(dev->dev_addr, &p->iph.saddr, 4); memcpy(dev->broadcast, &p->iph.daddr, 4); } ip_tunnel_add(itn, t); t->parms.iph.ttl = p->iph.ttl; t->parms.iph.tos = p->iph.tos; t->parms.iph.frag_off = p->iph.frag_off; |
9830ad4c6 ip_tunnel: Allow ... |
793 |
if (t->parms.link != p->link || t->fwmark != fwmark) { |
c54419321 GRE: Refactor GRE... |
794 795 796 |
int mtu; t->parms.link = p->link; |
9830ad4c6 ip_tunnel: Allow ... |
797 |
t->fwmark = fwmark; |
c54419321 GRE: Refactor GRE... |
798 799 800 801 |
mtu = ip_tunnel_bind_dev(dev); if (set_mtu) dev->mtu = mtu; } |
e09acddf8 ip_tunnel: replac... |
802 |
dst_cache_reset(&t->dst_cache); |
c54419321 GRE: Refactor GRE... |
803 804 805 806 807 808 |
netdev_state_change(dev); } int ip_tunnel_ioctl(struct net_device *dev, struct ip_tunnel_parm *p, int cmd) { int err = 0; |
8c923ce21 ip_tunnel: use th... |
809 810 811 |
struct ip_tunnel *t = netdev_priv(dev); struct net *net = t->net; struct ip_tunnel_net *itn = net_generic(net, t->ip_tnl_net_id); |
c54419321 GRE: Refactor GRE... |
812 813 814 815 |
BUG_ON(!itn->fb_tunnel_dev); switch (cmd) { case SIOCGETTUNNEL: |
8c923ce21 ip_tunnel: use th... |
816 |
if (dev == itn->fb_tunnel_dev) { |
c54419321 GRE: Refactor GRE... |
817 |
t = ip_tunnel_find(itn, p, itn->fb_tunnel_dev->type); |
51456b291 ipv4: coding styl... |
818 |
if (!t) |
8c923ce21 ip_tunnel: use th... |
819 820 |
t = netdev_priv(dev); } |
c54419321 GRE: Refactor GRE... |
821 822 823 824 825 826 827 828 829 830 |
memcpy(p, &t->parms, sizeof(*p)); break; case SIOCADDTUNNEL: case SIOCCHGTUNNEL: err = -EPERM; if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) goto done; if (p->iph.ttl) p->iph.frag_off |= htons(IP_DF); |
7c8e6b9c2 ip_vti: Fix 'ip t... |
831 832 833 834 835 836 |
if (!(p->i_flags & VTI_ISVTI)) { if (!(p->i_flags & TUNNEL_KEY)) p->i_key = 0; if (!(p->o_flags & TUNNEL_KEY)) p->o_key = 0; } |
c54419321 GRE: Refactor GRE... |
837 838 |
t = ip_tunnel_find(itn, p, itn->fb_tunnel_dev->type); |
d61746b2e ip_tunnel: Don't ... |
839 840 841 842 843 844 845 846 |
if (cmd == SIOCADDTUNNEL) { if (!t) { t = ip_tunnel_create(net, itn, p); err = PTR_ERR_OR_ZERO(t); break; } err = -EEXIST; |
ee30ef4d4 ip_tunnel: don't ... |
847 |
break; |
6dd3c9ec2 ip_tunnel: return... |
848 |
} |
c54419321 GRE: Refactor GRE... |
849 |
if (dev != itn->fb_tunnel_dev && cmd == SIOCCHGTUNNEL) { |
00db41243 ipv4: coding styl... |
850 |
if (t) { |
c54419321 GRE: Refactor GRE... |
851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 |
if (t->dev != dev) { err = -EEXIST; break; } } else { unsigned int nflags = 0; if (ipv4_is_multicast(p->iph.daddr)) nflags = IFF_BROADCAST; else if (p->iph.daddr) nflags = IFF_POINTOPOINT; if ((dev->flags^nflags)&(IFF_POINTOPOINT|IFF_BROADCAST)) { err = -EINVAL; break; } t = netdev_priv(dev); } } if (t) { err = 0; |
9830ad4c6 ip_tunnel: Allow ... |
874 |
ip_tunnel_update(itn, t, dev, p, true, 0); |
6dd3c9ec2 ip_tunnel: return... |
875 876 877 |
} else { err = -ENOENT; } |
c54419321 GRE: Refactor GRE... |
878 879 880 881 882 883 884 885 886 887 |
break; case SIOCDELTUNNEL: err = -EPERM; if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) goto done; if (dev == itn->fb_tunnel_dev) { err = -ENOENT; t = ip_tunnel_find(itn, p, itn->fb_tunnel_dev->type); |
51456b291 ipv4: coding styl... |
888 |
if (!t) |
c54419321 GRE: Refactor GRE... |
889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 |
goto done; err = -EPERM; if (t == netdev_priv(itn->fb_tunnel_dev)) goto done; dev = t->dev; } unregister_netdevice(dev); err = 0; break; default: err = -EINVAL; } done: return err; } EXPORT_SYMBOL_GPL(ip_tunnel_ioctl); |
7e059158d vxlan, gre, genev... |
907 |
int __ip_tunnel_change_mtu(struct net_device *dev, int new_mtu, bool strict) |
c54419321 GRE: Refactor GRE... |
908 909 910 |
{ struct ip_tunnel *tunnel = netdev_priv(dev); int t_hlen = tunnel->hlen + sizeof(struct iphdr); |
7e059158d vxlan, gre, genev... |
911 |
int max_mtu = 0xFFF8 - dev->hard_header_len - t_hlen; |
c54419321 GRE: Refactor GRE... |
912 |
|
b96f9afee ipv4/6: use core ... |
913 |
if (new_mtu < ETH_MIN_MTU) |
c54419321 GRE: Refactor GRE... |
914 |
return -EINVAL; |
7e059158d vxlan, gre, genev... |
915 916 917 918 919 920 921 |
if (new_mtu > max_mtu) { if (strict) return -EINVAL; new_mtu = max_mtu; } |
c54419321 GRE: Refactor GRE... |
922 923 924 |
dev->mtu = new_mtu; return 0; } |
7e059158d vxlan, gre, genev... |
925 926 927 928 929 930 |
EXPORT_SYMBOL_GPL(__ip_tunnel_change_mtu); int ip_tunnel_change_mtu(struct net_device *dev, int new_mtu) { return __ip_tunnel_change_mtu(dev, new_mtu, true); } |
c54419321 GRE: Refactor GRE... |
931 932 933 934 935 936 937 |
EXPORT_SYMBOL_GPL(ip_tunnel_change_mtu); static void ip_tunnel_dev_free(struct net_device *dev) { struct ip_tunnel *tunnel = netdev_priv(dev); gro_cells_destroy(&tunnel->gro_cells); |
e09acddf8 ip_tunnel: replac... |
938 |
dst_cache_destroy(&tunnel->dst_cache); |
c54419321 GRE: Refactor GRE... |
939 |
free_percpu(dev->tstats); |
c54419321 GRE: Refactor GRE... |
940 941 942 943 |
} void ip_tunnel_dellink(struct net_device *dev, struct list_head *head) { |
c54419321 GRE: Refactor GRE... |
944 945 |
struct ip_tunnel *tunnel = netdev_priv(dev); struct ip_tunnel_net *itn; |
6c742e714 ipip: add x-netns... |
946 |
itn = net_generic(tunnel->net, tunnel->ip_tnl_net_id); |
c54419321 GRE: Refactor GRE... |
947 948 |
if (itn->fb_tunnel_dev != dev) { |
2e15ea390 ip_gre: Add suppo... |
949 |
ip_tunnel_del(itn, netdev_priv(dev)); |
c54419321 GRE: Refactor GRE... |
950 951 952 953 |
unregister_netdevice_queue(dev, head); } } EXPORT_SYMBOL_GPL(ip_tunnel_dellink); |
1728d4fab tunnels: advertis... |
954 955 956 957 958 959 960 |
struct net *ip_tunnel_get_link_net(const struct net_device *dev) { struct ip_tunnel *tunnel = netdev_priv(dev); return tunnel->net; } EXPORT_SYMBOL(ip_tunnel_get_link_net); |
1e99584b9 ipip,gre,vti,sit:... |
961 962 963 964 965 966 967 |
int ip_tunnel_get_iflink(const struct net_device *dev) { struct ip_tunnel *tunnel = netdev_priv(dev); return tunnel->parms.link; } EXPORT_SYMBOL(ip_tunnel_get_iflink); |
c7d03a00b netns: make struc... |
968 |
int ip_tunnel_init_net(struct net *net, unsigned int ip_tnl_net_id, |
c54419321 GRE: Refactor GRE... |
969 970 971 972 |
struct rtnl_link_ops *ops, char *devname) { struct ip_tunnel_net *itn = net_generic(net, ip_tnl_net_id); struct ip_tunnel_parm parms; |
6261d983f ip_tunnel: embed ... |
973 |
unsigned int i; |
c54419321 GRE: Refactor GRE... |
974 |
|
6261d983f ip_tunnel: embed ... |
975 976 |
for (i = 0; i < IP_TNL_HASH_SIZE; i++) INIT_HLIST_HEAD(&itn->tunnels[i]); |
c54419321 GRE: Refactor GRE... |
977 978 979 980 981 |
if (!ops) { itn->fb_tunnel_dev = NULL; return 0; } |
6261d983f ip_tunnel: embed ... |
982 |
|
c54419321 GRE: Refactor GRE... |
983 984 985 986 987 988 |
memset(&parms, 0, sizeof(parms)); if (devname) strlcpy(parms.name, devname, IFNAMSIZ); rtnl_lock(); itn->fb_tunnel_dev = __ip_tunnel_create(net, ops, &parms); |
ea857f28a ipip: dereferenci... |
989 990 991 |
/* FB netdevice is special: we have one, and only one per netns. * Allowing to move it to another netns is clearly unsafe. */ |
670132826 ip_tunnel: Add fa... |
992 |
if (!IS_ERR(itn->fb_tunnel_dev)) { |
b4de77ade ipip: potential r... |
993 |
itn->fb_tunnel_dev->features |= NETIF_F_NETNS_LOCAL; |
78ff4be45 ip_tunnel: Initia... |
994 |
itn->fb_tunnel_dev->mtu = ip_tunnel_bind_dev(itn->fb_tunnel_dev); |
670132826 ip_tunnel: Add fa... |
995 996 |
ip_tunnel_add(itn, netdev_priv(itn->fb_tunnel_dev)); } |
b4de77ade ipip: potential r... |
997 |
rtnl_unlock(); |
c54419321 GRE: Refactor GRE... |
998 |
|
27d79f3b1 net: ipv4: Use PT... |
999 |
return PTR_ERR_OR_ZERO(itn->fb_tunnel_dev); |
c54419321 GRE: Refactor GRE... |
1000 1001 |
} EXPORT_SYMBOL_GPL(ip_tunnel_init_net); |
6c742e714 ipip: add x-netns... |
1002 1003 |
static void ip_tunnel_destroy(struct ip_tunnel_net *itn, struct list_head *head, struct rtnl_link_ops *ops) |
c54419321 GRE: Refactor GRE... |
1004 |
{ |
6c742e714 ipip: add x-netns... |
1005 1006 |
struct net *net = dev_net(itn->fb_tunnel_dev); struct net_device *dev, *aux; |
c54419321 GRE: Refactor GRE... |
1007 |
int h; |
6c742e714 ipip: add x-netns... |
1008 1009 1010 |
for_each_netdev_safe(net, dev, aux) if (dev->rtnl_link_ops == ops) unregister_netdevice_queue(dev, head); |
c54419321 GRE: Refactor GRE... |
1011 1012 1013 1014 1015 1016 |
for (h = 0; h < IP_TNL_HASH_SIZE; h++) { struct ip_tunnel *t; struct hlist_node *n; struct hlist_head *thead = &itn->tunnels[h]; hlist_for_each_entry_safe(t, n, thead, hash_node) |
6c742e714 ipip: add x-netns... |
1017 1018 1019 1020 1021 |
/* If dev is in the same netns, it has already * been added to the list by the previous loop. */ if (!net_eq(dev_net(t->dev), net)) unregister_netdevice_queue(t->dev, head); |
c54419321 GRE: Refactor GRE... |
1022 |
} |
c54419321 GRE: Refactor GRE... |
1023 |
} |
6c742e714 ipip: add x-netns... |
1024 |
void ip_tunnel_delete_net(struct ip_tunnel_net *itn, struct rtnl_link_ops *ops) |
c54419321 GRE: Refactor GRE... |
1025 1026 1027 1028 |
{ LIST_HEAD(list); rtnl_lock(); |
6c742e714 ipip: add x-netns... |
1029 |
ip_tunnel_destroy(itn, &list, ops); |
c54419321 GRE: Refactor GRE... |
1030 1031 |
unregister_netdevice_many(&list); rtnl_unlock(); |
c54419321 GRE: Refactor GRE... |
1032 1033 1034 1035 |
} EXPORT_SYMBOL_GPL(ip_tunnel_delete_net); int ip_tunnel_newlink(struct net_device *dev, struct nlattr *tb[], |
9830ad4c6 ip_tunnel: Allow ... |
1036 |
struct ip_tunnel_parm *p, __u32 fwmark) |
c54419321 GRE: Refactor GRE... |
1037 1038 1039 1040 1041 1042 1043 1044 1045 |
{ struct ip_tunnel *nt; struct net *net = dev_net(dev); struct ip_tunnel_net *itn; int mtu; int err; nt = netdev_priv(dev); itn = net_generic(net, nt->ip_tnl_net_id); |
2e15ea390 ip_gre: Add suppo... |
1046 1047 1048 1049 1050 1051 1052 |
if (nt->collect_md) { if (rtnl_dereference(itn->collect_md_tun)) return -EEXIST; } else { if (ip_tunnel_find(itn, p, dev->type)) return -EEXIST; } |
c54419321 GRE: Refactor GRE... |
1053 |
|
5e6700b3b sit: add support ... |
1054 |
nt->net = net; |
c54419321 GRE: Refactor GRE... |
1055 |
nt->parms = *p; |
9830ad4c6 ip_tunnel: Allow ... |
1056 |
nt->fwmark = fwmark; |
c54419321 GRE: Refactor GRE... |
1057 1058 1059 1060 1061 1062 1063 1064 |
err = register_netdevice(dev); if (err) goto out; if (dev->type == ARPHRD_ETHER && !tb[IFLA_ADDRESS]) eth_hw_addr_random(dev); mtu = ip_tunnel_bind_dev(dev); |
34b6ba622 ip_tunnel: Clamp ... |
1065 1066 1067 1068 1069 1070 |
if (tb[IFLA_MTU]) { unsigned int max = 0xfff8 - dev->hard_header_len - nt->hlen; dev->mtu = clamp(dev->mtu, (unsigned int)ETH_MIN_MTU, (unsigned int)(max - sizeof(struct iphdr))); } else { |
c54419321 GRE: Refactor GRE... |
1071 |
dev->mtu = mtu; |
34b6ba622 ip_tunnel: Clamp ... |
1072 |
} |
c54419321 GRE: Refactor GRE... |
1073 1074 |
ip_tunnel_add(itn, nt); |
c54419321 GRE: Refactor GRE... |
1075 1076 1077 1078 1079 1080 |
out: return err; } EXPORT_SYMBOL_GPL(ip_tunnel_newlink); int ip_tunnel_changelink(struct net_device *dev, struct nlattr *tb[], |
9830ad4c6 ip_tunnel: Allow ... |
1081 |
struct ip_tunnel_parm *p, __u32 fwmark) |
c54419321 GRE: Refactor GRE... |
1082 |
{ |
6c742e714 ipip: add x-netns... |
1083 |
struct ip_tunnel *t; |
c54419321 GRE: Refactor GRE... |
1084 |
struct ip_tunnel *tunnel = netdev_priv(dev); |
6c742e714 ipip: add x-netns... |
1085 |
struct net *net = tunnel->net; |
c54419321 GRE: Refactor GRE... |
1086 1087 1088 1089 |
struct ip_tunnel_net *itn = net_generic(net, tunnel->ip_tnl_net_id); if (dev == itn->fb_tunnel_dev) return -EINVAL; |
c54419321 GRE: Refactor GRE... |
1090 1091 1092 1093 1094 1095 |
t = ip_tunnel_find(itn, p, dev->type); if (t) { if (t->dev != dev) return -EEXIST; } else { |
6c742e714 ipip: add x-netns... |
1096 |
t = tunnel; |
c54419321 GRE: Refactor GRE... |
1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 |
if (dev->type != ARPHRD_ETHER) { unsigned int nflags = 0; if (ipv4_is_multicast(p->iph.daddr)) nflags = IFF_BROADCAST; else if (p->iph.daddr) nflags = IFF_POINTOPOINT; if ((dev->flags ^ nflags) & (IFF_POINTOPOINT | IFF_BROADCAST)) return -EINVAL; } } |
9830ad4c6 ip_tunnel: Allow ... |
1111 |
ip_tunnel_update(itn, t, dev, p, !tb[IFLA_MTU], fwmark); |
c54419321 GRE: Refactor GRE... |
1112 1113 1114 1115 1116 1117 1118 1119 |
return 0; } EXPORT_SYMBOL_GPL(ip_tunnel_changelink); int ip_tunnel_init(struct net_device *dev) { struct ip_tunnel *tunnel = netdev_priv(dev); struct iphdr *iph = &tunnel->parms.iph; |
1c213bd24 net: introduce ne... |
1120 |
int err; |
c54419321 GRE: Refactor GRE... |
1121 |
|
cf124db56 net: Fix inconsis... |
1122 1123 |
dev->needs_free_netdev = true; dev->priv_destructor = ip_tunnel_dev_free; |
1c213bd24 net: introduce ne... |
1124 |
dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); |
c54419321 GRE: Refactor GRE... |
1125 1126 |
if (!dev->tstats) return -ENOMEM; |
e09acddf8 ip_tunnel: replac... |
1127 1128 |
err = dst_cache_init(&tunnel->dst_cache, GFP_KERNEL); if (err) { |
9a4aa9af4 ipv4: Use percpu ... |
1129 |
free_percpu(dev->tstats); |
e09acddf8 ip_tunnel: replac... |
1130 |
return err; |
9a4aa9af4 ipv4: Use percpu ... |
1131 |
} |
c54419321 GRE: Refactor GRE... |
1132 1133 |
err = gro_cells_init(&tunnel->gro_cells, dev); if (err) { |
e09acddf8 ip_tunnel: replac... |
1134 |
dst_cache_destroy(&tunnel->dst_cache); |
c54419321 GRE: Refactor GRE... |
1135 1136 1137 1138 1139 |
free_percpu(dev->tstats); return err; } tunnel->dev = dev; |
6c742e714 ipip: add x-netns... |
1140 |
tunnel->net = dev_net(dev); |
c54419321 GRE: Refactor GRE... |
1141 1142 1143 |
strcpy(tunnel->parms.name, dev->name); iph->version = 4; iph->ihl = 5; |
2e15ea390 ip_gre: Add suppo... |
1144 1145 1146 1147 |
if (tunnel->collect_md) { dev->features |= NETIF_F_NETNS_LOCAL; netif_keep_dst(dev); } |
c54419321 GRE: Refactor GRE... |
1148 1149 1150 1151 1152 1153 |
return 0; } EXPORT_SYMBOL_GPL(ip_tunnel_init); void ip_tunnel_uninit(struct net_device *dev) { |
c54419321 GRE: Refactor GRE... |
1154 |
struct ip_tunnel *tunnel = netdev_priv(dev); |
6c742e714 ipip: add x-netns... |
1155 |
struct net *net = tunnel->net; |
c54419321 GRE: Refactor GRE... |
1156 1157 1158 1159 1160 |
struct ip_tunnel_net *itn; itn = net_generic(net, tunnel->ip_tnl_net_id); /* fb_tunnel_dev will be unregisted in net-exit call. */ if (itn->fb_tunnel_dev != dev) |
2e15ea390 ip_gre: Add suppo... |
1161 |
ip_tunnel_del(itn, netdev_priv(dev)); |
7d442fab0 ipv4: Cache dst i... |
1162 |
|
e09acddf8 ip_tunnel: replac... |
1163 |
dst_cache_reset(&tunnel->dst_cache); |
c54419321 GRE: Refactor GRE... |
1164 1165 1166 1167 |
} EXPORT_SYMBOL_GPL(ip_tunnel_uninit); /* Do least required initialization, rest of init is done in tunnel_init call */ |
c7d03a00b netns: make struc... |
1168 |
void ip_tunnel_setup(struct net_device *dev, unsigned int net_id) |
c54419321 GRE: Refactor GRE... |
1169 1170 1171 1172 1173 1174 1175 |
{ struct ip_tunnel *tunnel = netdev_priv(dev); tunnel->ip_tnl_net_id = net_id; } EXPORT_SYMBOL_GPL(ip_tunnel_setup); MODULE_LICENSE("GPL"); |