Blame view
net/ipv4/ip_gre.c
42.1 KB
1da177e4c Linux-2.6.12-rc2 |
1 |
/* |
e905a9eda [NET] IPV4: Fix w... |
2 |
* Linux NET3: GRE over IP protocol decoder. |
1da177e4c Linux-2.6.12-rc2 |
3 4 5 6 7 8 9 10 11 |
* * Authors: Alexey Kuznetsov (kuznet@ms2.inr.ac.ru) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * */ |
4fc268d24 [PATCH] capable/c... |
12 |
#include <linux/capability.h> |
1da177e4c Linux-2.6.12-rc2 |
13 14 |
#include <linux/module.h> #include <linux/types.h> |
1da177e4c Linux-2.6.12-rc2 |
15 |
#include <linux/kernel.h> |
5a0e3ad6a include cleanup: ... |
16 |
#include <linux/slab.h> |
1da177e4c Linux-2.6.12-rc2 |
17 18 19 20 21 22 23 24 25 26 27 28 29 |
#include <asm/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> #include <linux/mroute.h> #include <linux/init.h> #include <linux/in6.h> #include <linux/inetdevice.h> #include <linux/igmp.h> #include <linux/netfilter_ipv4.h> |
e1a800022 gre: Add Transpar... |
30 |
#include <linux/etherdevice.h> |
46f25dffb [NET]: Change 150... |
31 |
#include <linux/if_ether.h> |
1da177e4c Linux-2.6.12-rc2 |
32 33 34 35 36 37 38 39 40 41 42 |
#include <net/sock.h> #include <net/ip.h> #include <net/icmp.h> #include <net/protocol.h> #include <net/ipip.h> #include <net/arp.h> #include <net/checksum.h> #include <net/dsfield.h> #include <net/inet_ecn.h> #include <net/xfrm.h> |
59a4c7594 [GRE]: Introduce ... |
43 44 |
#include <net/net_namespace.h> #include <net/netns/generic.h> |
c19e654dd gre: Add netlink ... |
45 |
#include <net/rtnetlink.h> |
00959ade3 PPTP: PPP over IP... |
46 |
#include <net/gre.h> |
1da177e4c Linux-2.6.12-rc2 |
47 |
|
dfd56b8b3 net: use IS_ENABL... |
48 |
#if IS_ENABLED(CONFIG_IPV6) |
1da177e4c Linux-2.6.12-rc2 |
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
#include <net/ipv6.h> #include <net/ip6_fib.h> #include <net/ip6_route.h> #endif /* Problems & solutions -------------------- 1. The most important issue is detecting local dead loops. They would cause complete host lockup in transmit, which would be "resolved" by stack overflow or, if queueing is enabled, with infinite looping in net_bh. We cannot track such dead loops during route installation, it is infeasible task. The most general solutions would be to keep skb->encapsulation counter (sort of local ttl), |
6d0722a2c ip_gre: comments ... |
66 |
and silently drop packet when it expires. It is a good |
1da177e4c Linux-2.6.12-rc2 |
67 68 |
solution, but it supposes maintaing new variable in ALL skb, even if no tunneling is used. |
6d0722a2c ip_gre: comments ... |
69 70 71 |
Current solution: xmit_recursion breaks dead loops. This is a percpu counter, since when we enter the first ndo_xmit(), cpu migration is forbidden. We force an exit if this counter reaches RECURSION_LIMIT |
1da177e4c Linux-2.6.12-rc2 |
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 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
2. Networking dead loops would not kill routers, but would really kill network. IP hop limit plays role of "t->recursion" in this case, if we copy it from packet being encapsulated to upper header. It is very good solution, but it introduces two problems: - Routing protocols, using packets with ttl=1 (OSPF, RIP2), do not work over tunnels. - traceroute does not work. I planned to relay ICMP from tunnel, so that this problem would be solved and traceroute output would even more informative. This idea appeared to be wrong: only Linux complies to rfc1812 now (yes, guys, Linux is the only true router now :-)), all routers (at least, in neighbourhood of mine) return only 8 bytes of payload. It is the end. Hence, if we want that OSPF worked or traceroute said something reasonable, we should search for another solution. One of them is to parse packet trying to detect inner encapsulation made by our node. It is difficult or even impossible, especially, taking into account fragmentation. TO be short, tt is not solution at all. Current solution: The solution was UNEXPECTEDLY SIMPLE. We force DF flag on tunnels with preconfigured hop limit, that is ALL. :-) Well, it does not remove the problem completely, but exponential growth of network traffic is changed to linear (branches, that exceed pmtu are pruned) and tunnel mtu fastly degrades to value <68, where looping stops. Yes, it is not good if there exists a router in the loop, which does not force DF, even when encapsulating packets have DF set. But it is not our problem! Nobody could accuse us, we made all that we could make. Even if it is your gated who injected fatal route to network, even if it were you who configured fatal static route: you are innocent. :-) 3. Really, ipv4/ipip.c, ipv4/ip_gre.c and ipv6/sit.c contain practically identical code. It would be good to glue them together, but it is not very evident, how to make them modular. sit is integral part of IPv6, ipip and gre are naturally modular. We could extract common parts (hash table, ioctl etc) to a separate module (ip_tunnel.c). Alexey Kuznetsov. */ |
c19e654dd gre: Add netlink ... |
118 |
static struct rtnl_link_ops ipgre_link_ops __read_mostly; |
1da177e4c Linux-2.6.12-rc2 |
119 120 |
static int ipgre_tunnel_init(struct net_device *dev); static void ipgre_tunnel_setup(struct net_device *dev); |
42aa91626 gre: Move MTU set... |
121 |
static int ipgre_tunnel_bind_dev(struct net_device *dev); |
1da177e4c Linux-2.6.12-rc2 |
122 123 |
/* Fallback tunnel: no source, no destination, no key, no options */ |
eb8ce741a [GRE]: Make tunne... |
124 |
#define HASH_SIZE 16 |
f99189b18 netns: net_identi... |
125 |
static int ipgre_net_id __read_mostly; |
59a4c7594 [GRE]: Introduce ... |
126 |
struct ipgre_net { |
1507850b4 gre: get rid of i... |
127 |
struct ip_tunnel __rcu *tunnels[4][HASH_SIZE]; |
eb8ce741a [GRE]: Make tunne... |
128 |
|
7daa00048 [GRE]: Make the f... |
129 |
struct net_device *fb_tunnel_dev; |
59a4c7594 [GRE]: Introduce ... |
130 |
}; |
1da177e4c Linux-2.6.12-rc2 |
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 |
/* Tunnel hash table */ /* 4 hash tables: 3: (remote,local) 2: (remote,*) 1: (*,local) 0: (*,*) 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. */ |
d5a0a1e31 [IPV4]: encapsula... |
148 |
#define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF) |
1da177e4c Linux-2.6.12-rc2 |
149 |
|
eb8ce741a [GRE]: Make tunne... |
150 151 152 153 |
#define tunnels_r_l tunnels[3] #define tunnels_r tunnels[2] #define tunnels_l tunnels[1] #define tunnels_wc tunnels[0] |
8d5b2c084 gre: convert hash... |
154 |
/* |
1507850b4 gre: get rid of i... |
155 |
* Locking : hash tables are protected by RCU and RTNL |
8d5b2c084 gre: convert hash... |
156 |
*/ |
1da177e4c Linux-2.6.12-rc2 |
157 |
|
8d5b2c084 gre: convert hash... |
158 159 |
#define for_each_ip_tunnel_rcu(start) \ for (t = rcu_dereference(start); t; t = rcu_dereference(t->next)) |
1da177e4c Linux-2.6.12-rc2 |
160 |
|
e985aad72 ip_gre: percpu st... |
161 162 163 164 165 166 |
/* often modified stats are per cpu, other are shared (netdev->stats) */ struct pcpu_tstats { unsigned long rx_packets; unsigned long rx_bytes; unsigned long tx_packets; unsigned long tx_bytes; |
8ce120f11 net: better pcpu ... |
167 |
} __attribute__((aligned(4*sizeof(unsigned long)))); |
e985aad72 ip_gre: percpu st... |
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 |
static struct net_device_stats *ipgre_get_stats(struct net_device *dev) { struct pcpu_tstats sum = { 0 }; int i; for_each_possible_cpu(i) { const struct pcpu_tstats *tstats = per_cpu_ptr(dev->tstats, i); sum.rx_packets += tstats->rx_packets; sum.rx_bytes += tstats->rx_bytes; sum.tx_packets += tstats->tx_packets; sum.tx_bytes += tstats->tx_bytes; } dev->stats.rx_packets = sum.rx_packets; dev->stats.rx_bytes = sum.rx_bytes; dev->stats.tx_packets = sum.tx_packets; dev->stats.tx_bytes = sum.tx_bytes; return &dev->stats; } |
1da177e4c Linux-2.6.12-rc2 |
188 |
/* Given src, dst and key, find appropriate for input tunnel. */ |
749c10f93 gre: strict physi... |
189 |
static struct ip_tunnel * ipgre_tunnel_lookup(struct net_device *dev, |
e1a800022 gre: Add Transpar... |
190 191 |
__be32 remote, __be32 local, __be32 key, __be16 gre_proto) |
1da177e4c Linux-2.6.12-rc2 |
192 |
{ |
749c10f93 gre: strict physi... |
193 194 |
struct net *net = dev_net(dev); int link = dev->ifindex; |
1507850b4 gre: get rid of i... |
195 196 |
unsigned int h0 = HASH(remote); unsigned int h1 = HASH(key); |
afcf12422 gre: optimize has... |
197 |
struct ip_tunnel *t, *cand = NULL; |
7daa00048 [GRE]: Make the f... |
198 |
struct ipgre_net *ign = net_generic(net, ipgre_net_id); |
e1a800022 gre: Add Transpar... |
199 200 |
int dev_type = (gre_proto == htons(ETH_P_TEB)) ? ARPHRD_ETHER : ARPHRD_IPGRE; |
afcf12422 gre: optimize has... |
201 |
int score, cand_score = 4; |
1da177e4c Linux-2.6.12-rc2 |
202 |
|
8d5b2c084 gre: convert hash... |
203 |
for_each_ip_tunnel_rcu(ign->tunnels_r_l[h0 ^ h1]) { |
749c10f93 gre: strict physi... |
204 205 206 207 208 209 210 211 212 |
if (local != t->parms.iph.saddr || remote != t->parms.iph.daddr || key != t->parms.i_key || !(t->dev->flags & IFF_UP)) continue; if (t->dev->type != ARPHRD_IPGRE && t->dev->type != dev_type) continue; |
afcf12422 gre: optimize has... |
213 |
score = 0; |
749c10f93 gre: strict physi... |
214 |
if (t->parms.link != link) |
afcf12422 gre: optimize has... |
215 |
score |= 1; |
749c10f93 gre: strict physi... |
216 |
if (t->dev->type != dev_type) |
afcf12422 gre: optimize has... |
217 218 |
score |= 2; if (score == 0) |
749c10f93 gre: strict physi... |
219 |
return t; |
afcf12422 gre: optimize has... |
220 221 222 223 224 |
if (score < cand_score) { cand = t; cand_score = score; } |
1da177e4c Linux-2.6.12-rc2 |
225 |
} |
e1a800022 gre: Add Transpar... |
226 |
|
8d5b2c084 gre: convert hash... |
227 |
for_each_ip_tunnel_rcu(ign->tunnels_r[h0 ^ h1]) { |
749c10f93 gre: strict physi... |
228 229 230 231 232 233 234 235 |
if (remote != t->parms.iph.daddr || key != t->parms.i_key || !(t->dev->flags & IFF_UP)) continue; if (t->dev->type != ARPHRD_IPGRE && t->dev->type != dev_type) continue; |
afcf12422 gre: optimize has... |
236 |
score = 0; |
749c10f93 gre: strict physi... |
237 |
if (t->parms.link != link) |
afcf12422 gre: optimize has... |
238 |
score |= 1; |
749c10f93 gre: strict physi... |
239 |
if (t->dev->type != dev_type) |
afcf12422 gre: optimize has... |
240 241 |
score |= 2; if (score == 0) |
749c10f93 gre: strict physi... |
242 |
return t; |
afcf12422 gre: optimize has... |
243 244 245 246 247 |
if (score < cand_score) { cand = t; cand_score = score; } |
1da177e4c Linux-2.6.12-rc2 |
248 |
} |
e1a800022 gre: Add Transpar... |
249 |
|
8d5b2c084 gre: convert hash... |
250 |
for_each_ip_tunnel_rcu(ign->tunnels_l[h1]) { |
749c10f93 gre: strict physi... |
251 252 253 254 255 256 257 258 259 260 |
if ((local != t->parms.iph.saddr && (local != t->parms.iph.daddr || !ipv4_is_multicast(local))) || key != t->parms.i_key || !(t->dev->flags & IFF_UP)) continue; if (t->dev->type != ARPHRD_IPGRE && t->dev->type != dev_type) continue; |
afcf12422 gre: optimize has... |
261 |
score = 0; |
749c10f93 gre: strict physi... |
262 |
if (t->parms.link != link) |
afcf12422 gre: optimize has... |
263 |
score |= 1; |
749c10f93 gre: strict physi... |
264 |
if (t->dev->type != dev_type) |
afcf12422 gre: optimize has... |
265 266 |
score |= 2; if (score == 0) |
749c10f93 gre: strict physi... |
267 |
return t; |
afcf12422 gre: optimize has... |
268 269 270 271 272 |
if (score < cand_score) { cand = t; cand_score = score; } |
1da177e4c Linux-2.6.12-rc2 |
273 |
} |
e1a800022 gre: Add Transpar... |
274 |
|
8d5b2c084 gre: convert hash... |
275 |
for_each_ip_tunnel_rcu(ign->tunnels_wc[h1]) { |
749c10f93 gre: strict physi... |
276 277 278 279 280 281 282 |
if (t->parms.i_key != key || !(t->dev->flags & IFF_UP)) continue; if (t->dev->type != ARPHRD_IPGRE && t->dev->type != dev_type) continue; |
afcf12422 gre: optimize has... |
283 |
score = 0; |
749c10f93 gre: strict physi... |
284 |
if (t->parms.link != link) |
afcf12422 gre: optimize has... |
285 |
score |= 1; |
749c10f93 gre: strict physi... |
286 |
if (t->dev->type != dev_type) |
afcf12422 gre: optimize has... |
287 288 |
score |= 2; if (score == 0) |
749c10f93 gre: strict physi... |
289 |
return t; |
afcf12422 gre: optimize has... |
290 291 292 293 294 |
if (score < cand_score) { cand = t; cand_score = score; } |
1da177e4c Linux-2.6.12-rc2 |
295 |
} |
afcf12422 gre: optimize has... |
296 297 |
if (cand != NULL) return cand; |
e1a800022 gre: Add Transpar... |
298 |
|
8d5b2c084 gre: convert hash... |
299 300 301 |
dev = ign->fb_tunnel_dev; if (dev->flags & IFF_UP) return netdev_priv(dev); |
749c10f93 gre: strict physi... |
302 |
|
1da177e4c Linux-2.6.12-rc2 |
303 304 |
return NULL; } |
1507850b4 gre: get rid of i... |
305 |
static struct ip_tunnel __rcu **__ipgre_bucket(struct ipgre_net *ign, |
f57e7d5a7 [GRE]: Add net/gr... |
306 |
struct ip_tunnel_parm *parms) |
1da177e4c Linux-2.6.12-rc2 |
307 |
{ |
5056a1ef9 [IPV4] IP_GRE: Un... |
308 309 310 |
__be32 remote = parms->iph.daddr; __be32 local = parms->iph.saddr; __be32 key = parms->i_key; |
1507850b4 gre: get rid of i... |
311 |
unsigned int h = HASH(key); |
1da177e4c Linux-2.6.12-rc2 |
312 313 314 315 |
int prio = 0; if (local) prio |= 1; |
f97c1e0c6 [IPV4] net/ipv4: ... |
316 |
if (remote && !ipv4_is_multicast(remote)) { |
1da177e4c Linux-2.6.12-rc2 |
317 318 319 |
prio |= 2; h ^= HASH(remote); } |
eb8ce741a [GRE]: Make tunne... |
320 |
return &ign->tunnels[prio][h]; |
1da177e4c Linux-2.6.12-rc2 |
321 |
} |
1507850b4 gre: get rid of i... |
322 |
static inline struct ip_tunnel __rcu **ipgre_bucket(struct ipgre_net *ign, |
f57e7d5a7 [GRE]: Add net/gr... |
323 |
struct ip_tunnel *t) |
5056a1ef9 [IPV4] IP_GRE: Un... |
324 |
{ |
f57e7d5a7 [GRE]: Add net/gr... |
325 |
return __ipgre_bucket(ign, &t->parms); |
5056a1ef9 [IPV4] IP_GRE: Un... |
326 |
} |
f57e7d5a7 [GRE]: Add net/gr... |
327 |
static void ipgre_tunnel_link(struct ipgre_net *ign, struct ip_tunnel *t) |
1da177e4c Linux-2.6.12-rc2 |
328 |
{ |
1507850b4 gre: get rid of i... |
329 |
struct ip_tunnel __rcu **tp = ipgre_bucket(ign, t); |
1da177e4c Linux-2.6.12-rc2 |
330 |
|
1507850b4 gre: get rid of i... |
331 |
rcu_assign_pointer(t->next, rtnl_dereference(*tp)); |
8d5b2c084 gre: convert hash... |
332 |
rcu_assign_pointer(*tp, t); |
1da177e4c Linux-2.6.12-rc2 |
333 |
} |
f57e7d5a7 [GRE]: Add net/gr... |
334 |
static void ipgre_tunnel_unlink(struct ipgre_net *ign, struct ip_tunnel *t) |
1da177e4c Linux-2.6.12-rc2 |
335 |
{ |
1507850b4 gre: get rid of i... |
336 337 338 339 340 341 342 343 |
struct ip_tunnel __rcu **tp; struct ip_tunnel *iter; for (tp = ipgre_bucket(ign, t); (iter = rtnl_dereference(*tp)) != NULL; tp = &iter->next) { if (t == iter) { rcu_assign_pointer(*tp, t->next); |
1da177e4c Linux-2.6.12-rc2 |
344 345 346 347 |
break; } } } |
e1a800022 gre: Add Transpar... |
348 349 350 |
static struct ip_tunnel *ipgre_tunnel_find(struct net *net, struct ip_tunnel_parm *parms, int type) |
1da177e4c Linux-2.6.12-rc2 |
351 |
{ |
d5a0a1e31 [IPV4]: encapsula... |
352 353 354 |
__be32 remote = parms->iph.daddr; __be32 local = parms->iph.saddr; __be32 key = parms->i_key; |
749c10f93 gre: strict physi... |
355 |
int link = parms->link; |
1507850b4 gre: get rid of i... |
356 357 |
struct ip_tunnel *t; struct ip_tunnel __rcu **tp; |
e1a800022 gre: Add Transpar... |
358 |
struct ipgre_net *ign = net_generic(net, ipgre_net_id); |
1507850b4 gre: get rid of i... |
359 360 361 |
for (tp = __ipgre_bucket(ign, parms); (t = rtnl_dereference(*tp)) != NULL; tp = &t->next) |
e1a800022 gre: Add Transpar... |
362 363 364 |
if (local == t->parms.iph.saddr && remote == t->parms.iph.daddr && key == t->parms.i_key && |
749c10f93 gre: strict physi... |
365 |
link == t->parms.link && |
e1a800022 gre: Add Transpar... |
366 367 368 369 370 |
type == t->dev->type) break; return t; } |
1507850b4 gre: get rid of i... |
371 |
static struct ip_tunnel *ipgre_tunnel_locate(struct net *net, |
e1a800022 gre: Add Transpar... |
372 373 374 |
struct ip_tunnel_parm *parms, int create) { struct ip_tunnel *t, *nt; |
1da177e4c Linux-2.6.12-rc2 |
375 |
struct net_device *dev; |
1da177e4c Linux-2.6.12-rc2 |
376 |
char name[IFNAMSIZ]; |
f57e7d5a7 [GRE]: Add net/gr... |
377 |
struct ipgre_net *ign = net_generic(net, ipgre_net_id); |
1da177e4c Linux-2.6.12-rc2 |
378 |
|
e1a800022 gre: Add Transpar... |
379 380 381 |
t = ipgre_tunnel_find(net, parms, ARPHRD_IPGRE); if (t || !create) return t; |
1da177e4c Linux-2.6.12-rc2 |
382 383 384 |
if (parms->name[0]) strlcpy(name, parms->name, IFNAMSIZ); |
34cc7ba63 [IP_TUNNEL]: Don'... |
385 |
else |
407d6fcbf gre: minor cleanups |
386 |
strcpy(name, "gre%d"); |
1da177e4c Linux-2.6.12-rc2 |
387 388 389 |
dev = alloc_netdev(sizeof(*t), name, ipgre_tunnel_setup); if (!dev) |
407d6fcbf gre: minor cleanups |
390 |
return NULL; |
1da177e4c Linux-2.6.12-rc2 |
391 |
|
0b67eceb1 [GRE]: Allow to c... |
392 |
dev_net_set(dev, net); |
2941a4863 [NET]: Convert ne... |
393 |
nt = netdev_priv(dev); |
1da177e4c Linux-2.6.12-rc2 |
394 |
nt->parms = *parms; |
c19e654dd gre: Add netlink ... |
395 |
dev->rtnl_link_ops = &ipgre_link_ops; |
1da177e4c Linux-2.6.12-rc2 |
396 |
|
42aa91626 gre: Move MTU set... |
397 |
dev->mtu = ipgre_tunnel_bind_dev(dev); |
b37d428b2 [INET]: Don't cre... |
398 399 |
if (register_netdevice(dev) < 0) goto failed_free; |
1da177e4c Linux-2.6.12-rc2 |
400 |
|
1da177e4c Linux-2.6.12-rc2 |
401 |
dev_hold(dev); |
f57e7d5a7 [GRE]: Add net/gr... |
402 |
ipgre_tunnel_link(ign, nt); |
1da177e4c Linux-2.6.12-rc2 |
403 |
return nt; |
b37d428b2 [INET]: Don't cre... |
404 405 |
failed_free: free_netdev(dev); |
1da177e4c Linux-2.6.12-rc2 |
406 407 408 409 410 |
return NULL; } static void ipgre_tunnel_uninit(struct net_device *dev) { |
f57e7d5a7 [GRE]: Add net/gr... |
411 412 413 414 |
struct net *net = dev_net(dev); struct ipgre_net *ign = net_generic(net, ipgre_net_id); ipgre_tunnel_unlink(ign, netdev_priv(dev)); |
1da177e4c Linux-2.6.12-rc2 |
415 416 417 418 419 420 |
dev_put(dev); } static void ipgre_err(struct sk_buff *skb, u32 info) { |
1da177e4c Linux-2.6.12-rc2 |
421 |
|
071f92d05 net: The world is... |
422 |
/* All the routers (except for Linux) return only |
1da177e4c Linux-2.6.12-rc2 |
423 424 425 426 427 428 429 430 431 432 433 |
8 bytes of packet payload. It means, that precise relaying of ICMP in the real Internet is absolutely infeasible. Moreover, Cisco "wise men" put GRE key to the third word in GRE header. It makes impossible maintaining even soft state for keyed GRE tunnels with enabled checksum. Tell them "thank you". Well, I wonder, rfc1812 was written by Cisco employee, what the hell these idiots break standrads established by themself??? */ |
b71d1d426 inet: constify ip... |
434 |
const struct iphdr *iph = (const struct iphdr *)skb->data; |
d5a0a1e31 [IPV4]: encapsula... |
435 |
__be16 *p = (__be16*)(skb->data+(iph->ihl<<2)); |
1da177e4c Linux-2.6.12-rc2 |
436 |
int grehlen = (iph->ihl<<2) + 4; |
88c7664f1 [SK_BUFF]: Introd... |
437 438 |
const int type = icmp_hdr(skb)->type; const int code = icmp_hdr(skb)->code; |
1da177e4c Linux-2.6.12-rc2 |
439 |
struct ip_tunnel *t; |
d5a0a1e31 [IPV4]: encapsula... |
440 |
__be16 flags; |
1da177e4c Linux-2.6.12-rc2 |
441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 |
flags = p[0]; if (flags&(GRE_CSUM|GRE_KEY|GRE_SEQ|GRE_ROUTING|GRE_VERSION)) { if (flags&(GRE_VERSION|GRE_ROUTING)) return; if (flags&GRE_KEY) { grehlen += 4; if (flags&GRE_CSUM) grehlen += 4; } } /* If only 8 bytes returned, keyed message will be dropped here */ if (skb_headlen(skb) < grehlen) return; switch (type) { default: case ICMP_PARAMETERPROB: return; case ICMP_DEST_UNREACH: switch (code) { case ICMP_SR_FAILED: case ICMP_PORT_UNREACH: /* Impossible event. */ return; case ICMP_FRAG_NEEDED: /* Soft state for pmtu is maintained by IP core. */ return; default: /* All others are translated to HOST_UNREACH. rfc2003 contains "deep thoughts" about NET_UNREACH, I believe they are just ether pollution. --ANK */ break; } break; case ICMP_TIME_EXCEEDED: if (code != ICMP_EXC_TTL) return; break; } |
8d5b2c084 gre: convert hash... |
484 |
rcu_read_lock(); |
749c10f93 gre: strict physi... |
485 |
t = ipgre_tunnel_lookup(skb->dev, iph->daddr, iph->saddr, |
e1a800022 gre: Add Transpar... |
486 487 488 |
flags & GRE_KEY ? *(((__be32 *)p) + (grehlen / 4) - 1) : 0, p[1]); |
f97c1e0c6 [IPV4] net/ipv4: ... |
489 490 |
if (t == NULL || t->parms.iph.daddr == 0 || ipv4_is_multicast(t->parms.iph.daddr)) |
1da177e4c Linux-2.6.12-rc2 |
491 492 493 494 |
goto out; if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED) goto out; |
da6185d87 gre: used time_be... |
495 |
if (time_before(jiffies, t->err_time + IPTUNNEL_ERR_TIMEO)) |
1da177e4c Linux-2.6.12-rc2 |
496 497 498 499 500 |
t->err_count++; else t->err_count = 1; t->err_time = jiffies; out: |
8d5b2c084 gre: convert hash... |
501 |
rcu_read_unlock(); |
1da177e4c Linux-2.6.12-rc2 |
502 |
} |
b71d1d426 inet: constify ip... |
503 |
static inline void ipgre_ecn_decapsulate(const struct iphdr *iph, struct sk_buff *skb) |
1da177e4c Linux-2.6.12-rc2 |
504 505 506 |
{ if (INET_ECN_is_ce(iph->tos)) { if (skb->protocol == htons(ETH_P_IP)) { |
eddc9ec53 [SK_BUFF]: Introd... |
507 |
IP_ECN_set_ce(ip_hdr(skb)); |
1da177e4c Linux-2.6.12-rc2 |
508 |
} else if (skb->protocol == htons(ETH_P_IPV6)) { |
0660e03f6 [SK_BUFF]: Introd... |
509 |
IP6_ECN_set_ce(ipv6_hdr(skb)); |
1da177e4c Linux-2.6.12-rc2 |
510 511 512 513 514 |
} } } static inline u8 |
b71d1d426 inet: constify ip... |
515 |
ipgre_ecn_encapsulate(u8 tos, const struct iphdr *old_iph, struct sk_buff *skb) |
1da177e4c Linux-2.6.12-rc2 |
516 517 518 519 520 |
{ u8 inner = 0; if (skb->protocol == htons(ETH_P_IP)) inner = old_iph->tos; else if (skb->protocol == htons(ETH_P_IPV6)) |
b71d1d426 inet: constify ip... |
521 |
inner = ipv6_get_dsfield((const struct ipv6hdr *)old_iph); |
1da177e4c Linux-2.6.12-rc2 |
522 523 524 525 526 |
return INET_ECN_encapsulate(tos, inner); } static int ipgre_rcv(struct sk_buff *skb) { |
b71d1d426 inet: constify ip... |
527 |
const struct iphdr *iph; |
1da177e4c Linux-2.6.12-rc2 |
528 |
u8 *h; |
d5a0a1e31 [IPV4]: encapsula... |
529 |
__be16 flags; |
d3bc23e7e [NET]: Annotate c... |
530 |
__sum16 csum = 0; |
d5a0a1e31 [IPV4]: encapsula... |
531 |
__be32 key = 0; |
1da177e4c Linux-2.6.12-rc2 |
532 533 534 |
u32 seqno = 0; struct ip_tunnel *tunnel; int offset = 4; |
e1a800022 gre: Add Transpar... |
535 |
__be16 gre_proto; |
1da177e4c Linux-2.6.12-rc2 |
536 537 538 |
if (!pskb_may_pull(skb, 16)) goto drop_nolock; |
eddc9ec53 [SK_BUFF]: Introd... |
539 |
iph = ip_hdr(skb); |
1da177e4c Linux-2.6.12-rc2 |
540 |
h = skb->data; |
d5a0a1e31 [IPV4]: encapsula... |
541 |
flags = *(__be16*)h; |
1da177e4c Linux-2.6.12-rc2 |
542 543 544 545 546 547 548 549 550 |
if (flags&(GRE_CSUM|GRE_KEY|GRE_ROUTING|GRE_SEQ|GRE_VERSION)) { /* - Version must be 0. - We do not support routing headers. */ if (flags&(GRE_VERSION|GRE_ROUTING)) goto drop_nolock; if (flags&GRE_CSUM) { |
fb286bb29 [NET]: Detect har... |
551 |
switch (skb->ip_summed) { |
84fa7933a [NET]: Replace CH... |
552 |
case CHECKSUM_COMPLETE: |
d3bc23e7e [NET]: Annotate c... |
553 |
csum = csum_fold(skb->csum); |
fb286bb29 [NET]: Detect har... |
554 555 556 557 558 559 |
if (!csum) break; /* fall through */ case CHECKSUM_NONE: skb->csum = 0; csum = __skb_checksum_complete(skb); |
84fa7933a [NET]: Replace CH... |
560 |
skb->ip_summed = CHECKSUM_COMPLETE; |
1da177e4c Linux-2.6.12-rc2 |
561 562 563 564 |
} offset += 4; } if (flags&GRE_KEY) { |
d5a0a1e31 [IPV4]: encapsula... |
565 |
key = *(__be32*)(h + offset); |
1da177e4c Linux-2.6.12-rc2 |
566 567 568 |
offset += 4; } if (flags&GRE_SEQ) { |
d5a0a1e31 [IPV4]: encapsula... |
569 |
seqno = ntohl(*(__be32*)(h + offset)); |
1da177e4c Linux-2.6.12-rc2 |
570 571 572 |
offset += 4; } } |
e1a800022 gre: Add Transpar... |
573 |
gre_proto = *(__be16 *)(h + 2); |
8d5b2c084 gre: convert hash... |
574 |
rcu_read_lock(); |
749c10f93 gre: strict physi... |
575 |
if ((tunnel = ipgre_tunnel_lookup(skb->dev, |
e1a800022 gre: Add Transpar... |
576 577 |
iph->saddr, iph->daddr, key, gre_proto))) { |
e985aad72 ip_gre: percpu st... |
578 |
struct pcpu_tstats *tstats; |
addd68eb6 ipgre: Use on-dev... |
579 |
|
1da177e4c Linux-2.6.12-rc2 |
580 |
secpath_reset(skb); |
e1a800022 gre: Add Transpar... |
581 |
skb->protocol = gre_proto; |
1da177e4c Linux-2.6.12-rc2 |
582 583 584 585 |
/* WCCP version 1 and 2 protocol decoding. * - Change protocol to IP * - When dealing with WCCPv2, Skip extra 4 bytes in GRE header */ |
e1a800022 gre: Add Transpar... |
586 |
if (flags == 0 && gre_proto == htons(ETH_P_WCCP)) { |
496c98dff [NET]: Use hton{l... |
587 |
skb->protocol = htons(ETH_P_IP); |
e905a9eda [NET] IPV4: Fix w... |
588 |
if ((*(h + offset) & 0xF0) != 0x40) |
1da177e4c Linux-2.6.12-rc2 |
589 590 |
offset += 4; } |
1d0691674 [IPV4] ip_gre: se... |
591 |
skb->mac_header = skb->network_header; |
4209fb601 [SK_BUFF]: Use sk... |
592 |
__pskb_pull(skb, offset); |
9c70220b7 [SK_BUFF]: Introd... |
593 |
skb_postpull_rcsum(skb, skb_transport_header(skb), offset); |
1da177e4c Linux-2.6.12-rc2 |
594 595 |
skb->pkt_type = PACKET_HOST; #ifdef CONFIG_NET_IPGRE_BROADCAST |
f97c1e0c6 [IPV4] net/ipv4: ... |
596 |
if (ipv4_is_multicast(iph->daddr)) { |
1da177e4c Linux-2.6.12-rc2 |
597 |
/* Looped back packet, drop it! */ |
c75379676 ipv4: Make rt->fl... |
598 |
if (rt_is_output_route(skb_rtable(skb))) |
1da177e4c Linux-2.6.12-rc2 |
599 |
goto drop; |
e985aad72 ip_gre: percpu st... |
600 |
tunnel->dev->stats.multicast++; |
1da177e4c Linux-2.6.12-rc2 |
601 602 603 604 605 606 |
skb->pkt_type = PACKET_BROADCAST; } #endif if (((flags&GRE_CSUM) && csum) || (!(flags&GRE_CSUM) && tunnel->parms.i_flags&GRE_CSUM)) { |
e985aad72 ip_gre: percpu st... |
607 608 |
tunnel->dev->stats.rx_crc_errors++; tunnel->dev->stats.rx_errors++; |
1da177e4c Linux-2.6.12-rc2 |
609 610 611 612 613 |
goto drop; } if (tunnel->parms.i_flags&GRE_SEQ) { if (!(flags&GRE_SEQ) || (tunnel->i_seqno && (s32)(seqno - tunnel->i_seqno) < 0)) { |
e985aad72 ip_gre: percpu st... |
614 615 |
tunnel->dev->stats.rx_fifo_errors++; tunnel->dev->stats.rx_errors++; |
1da177e4c Linux-2.6.12-rc2 |
616 617 618 619 |
goto drop; } tunnel->i_seqno = seqno + 1; } |
e1a800022 gre: Add Transpar... |
620 621 622 623 |
/* Warning: All skb pointers will be invalidated! */ if (tunnel->dev->type == ARPHRD_ETHER) { if (!pskb_may_pull(skb, ETH_HLEN)) { |
e985aad72 ip_gre: percpu st... |
624 625 |
tunnel->dev->stats.rx_length_errors++; tunnel->dev->stats.rx_errors++; |
e1a800022 gre: Add Transpar... |
626 627 628 629 630 631 632 |
goto drop; } iph = ip_hdr(skb); skb->protocol = eth_type_trans(skb, tunnel->dev); skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN); } |
e985aad72 ip_gre: percpu st... |
633 634 635 636 637 |
tstats = this_cpu_ptr(tunnel->dev->tstats); tstats->rx_packets++; tstats->rx_bytes += skb->len; __skb_tunnel_rx(skb, tunnel->dev); |
e1a800022 gre: Add Transpar... |
638 639 |
skb_reset_network_header(skb); |
1da177e4c Linux-2.6.12-rc2 |
640 |
ipgre_ecn_decapsulate(iph, skb); |
e1a800022 gre: Add Transpar... |
641 |
|
caf586e5f net: add a core n... |
642 |
netif_rx(skb); |
8990f468a net: rx_dropped a... |
643 |
|
8d5b2c084 gre: convert hash... |
644 |
rcu_read_unlock(); |
8990f468a net: rx_dropped a... |
645 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
646 |
} |
45af08be6 [INET]: Use port ... |
647 |
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); |
1da177e4c Linux-2.6.12-rc2 |
648 649 |
drop: |
8d5b2c084 gre: convert hash... |
650 |
rcu_read_unlock(); |
1da177e4c Linux-2.6.12-rc2 |
651 652 |
drop_nolock: kfree_skb(skb); |
a02cec215 net: return opera... |
653 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
654 |
} |
6fef4c0c8 netdev: convert p... |
655 |
static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) |
1da177e4c Linux-2.6.12-rc2 |
656 |
{ |
2941a4863 [NET]: Convert ne... |
657 |
struct ip_tunnel *tunnel = netdev_priv(dev); |
e985aad72 ip_gre: percpu st... |
658 |
struct pcpu_tstats *tstats; |
b71d1d426 inet: constify ip... |
659 660 |
const struct iphdr *old_iph = ip_hdr(skb); const struct iphdr *tiph; |
cbb1e85f9 ipv4: Kill rt->rt... |
661 |
struct flowi4 fl4; |
1da177e4c Linux-2.6.12-rc2 |
662 |
u8 tos; |
d5a0a1e31 [IPV4]: encapsula... |
663 |
__be16 df; |
1da177e4c Linux-2.6.12-rc2 |
664 |
struct rtable *rt; /* Route to the other host */ |
1507850b4 gre: get rid of i... |
665 |
struct net_device *tdev; /* Device to other host */ |
1da177e4c Linux-2.6.12-rc2 |
666 |
struct iphdr *iph; /* Our new IP header */ |
c2636b4d9 [NET]: Treat the ... |
667 |
unsigned int max_headroom; /* The extra header space needed */ |
1da177e4c Linux-2.6.12-rc2 |
668 |
int gre_hlen; |
d5a0a1e31 [IPV4]: encapsula... |
669 |
__be32 dst; |
1da177e4c Linux-2.6.12-rc2 |
670 |
int mtu; |
e1a800022 gre: Add Transpar... |
671 672 673 674 |
if (dev->type == ARPHRD_ETHER) IPCB(skb)->flags = 0; if (dev->header_ops && dev->type == ARPHRD_IPGRE) { |
1da177e4c Linux-2.6.12-rc2 |
675 |
gre_hlen = 0; |
b71d1d426 inet: constify ip... |
676 |
tiph = (const struct iphdr *)skb->data; |
1da177e4c Linux-2.6.12-rc2 |
677 678 679 680 681 682 683 |
} else { gre_hlen = tunnel->hlen; tiph = &tunnel->parms.iph; } if ((dst = tiph->daddr) == 0) { /* NBMA tunnel */ |
adf30907d net: skb->dst acc... |
684 |
if (skb_dst(skb) == NULL) { |
e985aad72 ip_gre: percpu st... |
685 |
dev->stats.tx_fifo_errors++; |
1da177e4c Linux-2.6.12-rc2 |
686 687 688 689 |
goto tx_error; } if (skb->protocol == htons(ETH_P_IP)) { |
511c3f92a net: skb->rtable ... |
690 |
rt = skb_rtable(skb); |
1da177e4c Linux-2.6.12-rc2 |
691 692 693 |
if ((dst = rt->rt_gateway) == 0) goto tx_error_icmp; } |
dfd56b8b3 net: use IS_ENABL... |
694 |
#if IS_ENABLED(CONFIG_IPV6) |
1da177e4c Linux-2.6.12-rc2 |
695 |
else if (skb->protocol == htons(ETH_P_IPV6)) { |
272174550 net: Rename dst_g... |
696 |
struct neighbour *neigh = dst_get_neighbour_noref(skb_dst(skb)); |
b71d1d426 inet: constify ip... |
697 |
const struct in6_addr *addr6; |
1da177e4c Linux-2.6.12-rc2 |
698 |
int addr_type; |
1da177e4c Linux-2.6.12-rc2 |
699 700 701 |
if (neigh == NULL) goto tx_error; |
b71d1d426 inet: constify ip... |
702 |
addr6 = (const struct in6_addr *)&neigh->primary_key; |
1da177e4c Linux-2.6.12-rc2 |
703 704 705 |
addr_type = ipv6_addr_type(addr6); if (addr_type == IPV6_ADDR_ANY) { |
0660e03f6 [SK_BUFF]: Introd... |
706 |
addr6 = &ipv6_hdr(skb)->daddr; |
1da177e4c Linux-2.6.12-rc2 |
707 708 709 710 711 712 713 714 715 716 717 718 719 720 |
addr_type = ipv6_addr_type(addr6); } if ((addr_type & IPV6_ADDR_COMPATv4) == 0) goto tx_error_icmp; dst = addr6->s6_addr32[3]; } #endif else goto tx_error; } tos = tiph->tos; |
ee686ca91 gre: fix ToS/Diff... |
721 722 |
if (tos == 1) { tos = 0; |
1da177e4c Linux-2.6.12-rc2 |
723 724 |
if (skb->protocol == htons(ETH_P_IP)) tos = old_iph->tos; |
dd4ba83dc gre: propagate ip... |
725 |
else if (skb->protocol == htons(ETH_P_IPV6)) |
b71d1d426 inet: constify ip... |
726 |
tos = ipv6_get_dsfield((const struct ipv6hdr *)old_iph); |
1da177e4c Linux-2.6.12-rc2 |
727 |
} |
cbb1e85f9 ipv4: Kill rt->rt... |
728 |
rt = ip_route_output_gre(dev_net(dev), &fl4, dst, tiph->saddr, |
78fbfd8a6 ipv4: Create and ... |
729 730 731 732 733 |
tunnel->parms.o_key, RT_TOS(tos), tunnel->parms.link); if (IS_ERR(rt)) { dev->stats.tx_carrier_errors++; goto tx_error; |
1da177e4c Linux-2.6.12-rc2 |
734 |
} |
d8d1f30b9 net-next: remove ... |
735 |
tdev = rt->dst.dev; |
1da177e4c Linux-2.6.12-rc2 |
736 737 738 |
if (tdev == dev) { ip_rt_put(rt); |
e985aad72 ip_gre: percpu st... |
739 |
dev->stats.collisions++; |
1da177e4c Linux-2.6.12-rc2 |
740 741 742 743 744 |
goto tx_error; } df = tiph->frag_off; if (df) |
d8d1f30b9 net-next: remove ... |
745 |
mtu = dst_mtu(&rt->dst) - dev->hard_header_len - tunnel->hlen; |
1da177e4c Linux-2.6.12-rc2 |
746 |
else |
adf30907d net: skb->dst acc... |
747 |
mtu = skb_dst(skb) ? dst_mtu(skb_dst(skb)) : dev->mtu; |
1da177e4c Linux-2.6.12-rc2 |
748 |
|
adf30907d net: skb->dst acc... |
749 750 |
if (skb_dst(skb)) skb_dst(skb)->ops->update_pmtu(skb_dst(skb), mtu); |
1da177e4c Linux-2.6.12-rc2 |
751 752 753 754 755 756 757 758 759 760 761 |
if (skb->protocol == htons(ETH_P_IP)) { df |= (old_iph->frag_off&htons(IP_DF)); if ((old_iph->frag_off&htons(IP_DF)) && mtu < ntohs(old_iph->tot_len)) { icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu)); ip_rt_put(rt); goto tx_error; } } |
dfd56b8b3 net: use IS_ENABL... |
762 |
#if IS_ENABLED(CONFIG_IPV6) |
1da177e4c Linux-2.6.12-rc2 |
763 |
else if (skb->protocol == htons(ETH_P_IPV6)) { |
adf30907d net: skb->dst acc... |
764 |
struct rt6_info *rt6 = (struct rt6_info *)skb_dst(skb); |
1da177e4c Linux-2.6.12-rc2 |
765 |
|
adf30907d net: skb->dst acc... |
766 |
if (rt6 && mtu < dst_mtu(skb_dst(skb)) && mtu >= IPV6_MIN_MTU) { |
f97c1e0c6 [IPV4] net/ipv4: ... |
767 768 |
if ((tunnel->parms.iph.daddr && !ipv4_is_multicast(tunnel->parms.iph.daddr)) || |
1da177e4c Linux-2.6.12-rc2 |
769 770 |
rt6->rt6i_dst.plen == 128) { rt6->rt6i_flags |= RTF_MODIFIED; |
defb3519a net: Abstract awa... |
771 |
dst_metric_set(skb_dst(skb), RTAX_MTU, mtu); |
1da177e4c Linux-2.6.12-rc2 |
772 773 774 775 |
} } if (mtu >= IPV6_MIN_MTU && mtu < skb->len - tunnel->hlen + gre_hlen) { |
3ffe533c8 ipv6: drop unused... |
776 |
icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); |
1da177e4c Linux-2.6.12-rc2 |
777 778 779 780 781 782 783 |
ip_rt_put(rt); goto tx_error; } } #endif if (tunnel->err_count > 0) { |
da6185d87 gre: used time_be... |
784 785 |
if (time_before(jiffies, tunnel->err_time + IPTUNNEL_ERR_TIMEO)) { |
1da177e4c Linux-2.6.12-rc2 |
786 787 788 789 790 791 |
tunnel->err_count--; dst_link_failure(skb); } else tunnel->err_count = 0; } |
d8d1f30b9 net-next: remove ... |
792 |
max_headroom = LL_RESERVED_SPACE(tdev) + gre_hlen + rt->dst.header_len; |
1da177e4c Linux-2.6.12-rc2 |
793 |
|
cfbba49d8 [NET]: Avoid copy... |
794 795 |
if (skb_headroom(skb) < max_headroom || skb_shared(skb)|| (skb_cloned(skb) && !skb_clone_writable(skb, 0))) { |
1da177e4c Linux-2.6.12-rc2 |
796 |
struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom); |
805dc1d60 ip_gre: Set neede... |
797 798 |
if (max_headroom > dev->needed_headroom) dev->needed_headroom = max_headroom; |
1da177e4c Linux-2.6.12-rc2 |
799 800 |
if (!new_skb) { ip_rt_put(rt); |
e985aad72 ip_gre: percpu st... |
801 |
dev->stats.tx_dropped++; |
1da177e4c Linux-2.6.12-rc2 |
802 |
dev_kfree_skb(skb); |
6ed106549 net: use NETDEV_T... |
803 |
return NETDEV_TX_OK; |
1da177e4c Linux-2.6.12-rc2 |
804 805 806 807 808 |
} if (skb->sk) skb_set_owner_w(new_skb, skb->sk); dev_kfree_skb(skb); skb = new_skb; |
eddc9ec53 [SK_BUFF]: Introd... |
809 |
old_iph = ip_hdr(skb); |
1da177e4c Linux-2.6.12-rc2 |
810 |
} |
64194c31a inet: Make tunnel... |
811 |
skb_reset_transport_header(skb); |
e2d1bca7e [SK_BUFF]: Use sk... |
812 813 |
skb_push(skb, gre_hlen); skb_reset_network_header(skb); |
1da177e4c Linux-2.6.12-rc2 |
814 |
memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); |
48d5cad87 [XFRM]: Fix SNAT-... |
815 816 |
IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED | IPSKB_REROUTED); |
adf30907d net: skb->dst acc... |
817 |
skb_dst_drop(skb); |
d8d1f30b9 net-next: remove ... |
818 |
skb_dst_set(skb, &rt->dst); |
1da177e4c Linux-2.6.12-rc2 |
819 820 821 822 |
/* * Push down and install the IPIP header. */ |
eddc9ec53 [SK_BUFF]: Introd... |
823 |
iph = ip_hdr(skb); |
1da177e4c Linux-2.6.12-rc2 |
824 825 826 827 828 |
iph->version = 4; iph->ihl = sizeof(struct iphdr) >> 2; iph->frag_off = df; iph->protocol = IPPROTO_GRE; iph->tos = ipgre_ecn_encapsulate(tos, old_iph, skb); |
cbb1e85f9 ipv4: Kill rt->rt... |
829 830 |
iph->daddr = fl4.daddr; iph->saddr = fl4.saddr; |
1da177e4c Linux-2.6.12-rc2 |
831 832 833 834 |
if ((iph->ttl = tiph->ttl) == 0) { if (skb->protocol == htons(ETH_P_IP)) iph->ttl = old_iph->ttl; |
dfd56b8b3 net: use IS_ENABL... |
835 |
#if IS_ENABLED(CONFIG_IPV6) |
1da177e4c Linux-2.6.12-rc2 |
836 |
else if (skb->protocol == htons(ETH_P_IPV6)) |
b71d1d426 inet: constify ip... |
837 |
iph->ttl = ((const struct ipv6hdr *)old_iph)->hop_limit; |
1da177e4c Linux-2.6.12-rc2 |
838 839 |
#endif else |
323e126f0 ipv4: Don't pre-s... |
840 |
iph->ttl = ip4_dst_hoplimit(&rt->dst); |
1da177e4c Linux-2.6.12-rc2 |
841 |
} |
e1a800022 gre: Add Transpar... |
842 843 844 |
((__be16 *)(iph + 1))[0] = tunnel->parms.o_flags; ((__be16 *)(iph + 1))[1] = (dev->type == ARPHRD_ETHER) ? htons(ETH_P_TEB) : skb->protocol; |
1da177e4c Linux-2.6.12-rc2 |
845 846 |
if (tunnel->parms.o_flags&(GRE_KEY|GRE_CSUM|GRE_SEQ)) { |
d5a0a1e31 [IPV4]: encapsula... |
847 |
__be32 *ptr = (__be32*)(((u8*)iph) + tunnel->hlen - 4); |
1da177e4c Linux-2.6.12-rc2 |
848 849 850 851 852 853 854 855 856 857 858 859 |
if (tunnel->parms.o_flags&GRE_SEQ) { ++tunnel->o_seqno; *ptr = htonl(tunnel->o_seqno); ptr--; } if (tunnel->parms.o_flags&GRE_KEY) { *ptr = tunnel->parms.o_key; ptr--; } if (tunnel->parms.o_flags&GRE_CSUM) { *ptr = 0; |
5f92a7388 [NET]: Annotate c... |
860 |
*(__sum16*)ptr = ip_compute_csum((void*)(iph+1), skb->len - sizeof(struct iphdr)); |
1da177e4c Linux-2.6.12-rc2 |
861 862 863 864 |
} } nf_reset(skb); |
e985aad72 ip_gre: percpu st... |
865 866 |
tstats = this_cpu_ptr(dev->tstats); __IPTUNNEL_XMIT(tstats, &dev->stats); |
6ed106549 net: use NETDEV_T... |
867 |
return NETDEV_TX_OK; |
1da177e4c Linux-2.6.12-rc2 |
868 869 870 871 872 |
tx_error_icmp: dst_link_failure(skb); tx_error: |
e985aad72 ip_gre: percpu st... |
873 |
dev->stats.tx_errors++; |
1da177e4c Linux-2.6.12-rc2 |
874 |
dev_kfree_skb(skb); |
6ed106549 net: use NETDEV_T... |
875 |
return NETDEV_TX_OK; |
1da177e4c Linux-2.6.12-rc2 |
876 |
} |
42aa91626 gre: Move MTU set... |
877 |
static int ipgre_tunnel_bind_dev(struct net_device *dev) |
ee34c1eb3 [IP_GRE]: Rebindi... |
878 879 880 |
{ struct net_device *tdev = NULL; struct ip_tunnel *tunnel; |
b71d1d426 inet: constify ip... |
881 |
const struct iphdr *iph; |
ee34c1eb3 [IP_GRE]: Rebindi... |
882 883 884 885 886 887 |
int hlen = LL_MAX_HEADER; int mtu = ETH_DATA_LEN; int addend = sizeof(struct iphdr) + 4; tunnel = netdev_priv(dev); iph = &tunnel->parms.iph; |
c95b819ad gre: Use needed_h... |
888 |
/* Guess output device to choose reasonable mtu and needed_headroom */ |
ee34c1eb3 [IP_GRE]: Rebindi... |
889 890 |
if (iph->daddr) { |
cbb1e85f9 ipv4: Kill rt->rt... |
891 892 893 894 895 896 897 898 |
struct flowi4 fl4; struct rtable *rt; rt = ip_route_output_gre(dev_net(dev), &fl4, iph->daddr, iph->saddr, tunnel->parms.o_key, RT_TOS(iph->tos), tunnel->parms.link); |
b23dd4fe4 ipv4: Make output... |
899 |
if (!IS_ERR(rt)) { |
d8d1f30b9 net-next: remove ... |
900 |
tdev = rt->dst.dev; |
ee34c1eb3 [IP_GRE]: Rebindi... |
901 902 |
ip_rt_put(rt); } |
e1a800022 gre: Add Transpar... |
903 904 905 |
if (dev->type != ARPHRD_ETHER) dev->flags |= IFF_POINTOPOINT; |
ee34c1eb3 [IP_GRE]: Rebindi... |
906 907 908 |
} if (!tdev && tunnel->parms.link) |
96635522f [GRE]: Use proper... |
909 |
tdev = __dev_get_by_index(dev_net(dev), tunnel->parms.link); |
ee34c1eb3 [IP_GRE]: Rebindi... |
910 911 |
if (tdev) { |
c95b819ad gre: Use needed_h... |
912 |
hlen = tdev->hard_header_len + tdev->needed_headroom; |
ee34c1eb3 [IP_GRE]: Rebindi... |
913 914 915 916 917 918 919 920 921 922 923 924 925 |
mtu = tdev->mtu; } dev->iflink = tunnel->parms.link; /* Precalculate GRE options length */ if (tunnel->parms.o_flags&(GRE_CSUM|GRE_KEY|GRE_SEQ)) { if (tunnel->parms.o_flags&GRE_CSUM) addend += 4; if (tunnel->parms.o_flags&GRE_KEY) addend += 4; if (tunnel->parms.o_flags&GRE_SEQ) addend += 4; } |
c95b819ad gre: Use needed_h... |
926 |
dev->needed_headroom = addend + hlen; |
8cdb04563 gre: Fix MTU calc... |
927 |
mtu -= dev->hard_header_len + addend; |
42aa91626 gre: Move MTU set... |
928 929 930 |
if (mtu < 68) mtu = 68; |
ee34c1eb3 [IP_GRE]: Rebindi... |
931 |
tunnel->hlen = addend; |
42aa91626 gre: Move MTU set... |
932 |
return mtu; |
ee34c1eb3 [IP_GRE]: Rebindi... |
933 |
} |
1da177e4c Linux-2.6.12-rc2 |
934 935 936 937 938 939 |
static int ipgre_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) { int err = 0; struct ip_tunnel_parm p; struct ip_tunnel *t; |
f57e7d5a7 [GRE]: Add net/gr... |
940 941 |
struct net *net = dev_net(dev); struct ipgre_net *ign = net_generic(net, ipgre_net_id); |
1da177e4c Linux-2.6.12-rc2 |
942 943 944 945 |
switch (cmd) { case SIOCGETTUNNEL: t = NULL; |
7daa00048 [GRE]: Make the f... |
946 |
if (dev == ign->fb_tunnel_dev) { |
1da177e4c Linux-2.6.12-rc2 |
947 948 949 950 |
if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) { err = -EFAULT; break; } |
f57e7d5a7 [GRE]: Add net/gr... |
951 |
t = ipgre_tunnel_locate(net, &p, 0); |
1da177e4c Linux-2.6.12-rc2 |
952 953 |
} if (t == NULL) |
2941a4863 [NET]: Convert ne... |
954 |
t = netdev_priv(dev); |
1da177e4c Linux-2.6.12-rc2 |
955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 |
memcpy(&p, &t->parms, sizeof(p)); if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p))) err = -EFAULT; break; case SIOCADDTUNNEL: case SIOCCHGTUNNEL: err = -EPERM; if (!capable(CAP_NET_ADMIN)) goto done; err = -EFAULT; if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) goto done; err = -EINVAL; if (p.iph.version != 4 || p.iph.protocol != IPPROTO_GRE || p.iph.ihl != 5 || (p.iph.frag_off&htons(~IP_DF)) || ((p.i_flags|p.o_flags)&(GRE_VERSION|GRE_ROUTING))) goto done; if (p.iph.ttl) p.iph.frag_off |= htons(IP_DF); if (!(p.i_flags&GRE_KEY)) p.i_key = 0; if (!(p.o_flags&GRE_KEY)) p.o_key = 0; |
f57e7d5a7 [GRE]: Add net/gr... |
982 |
t = ipgre_tunnel_locate(net, &p, cmd == SIOCADDTUNNEL); |
1da177e4c Linux-2.6.12-rc2 |
983 |
|
7daa00048 [GRE]: Make the f... |
984 |
if (dev != ign->fb_tunnel_dev && cmd == SIOCCHGTUNNEL) { |
1da177e4c Linux-2.6.12-rc2 |
985 986 987 988 989 990 |
if (t != NULL) { if (t->dev != dev) { err = -EEXIST; break; } } else { |
1507850b4 gre: get rid of i... |
991 |
unsigned int nflags = 0; |
1da177e4c Linux-2.6.12-rc2 |
992 |
|
2941a4863 [NET]: Convert ne... |
993 |
t = netdev_priv(dev); |
1da177e4c Linux-2.6.12-rc2 |
994 |
|
f97c1e0c6 [IPV4] net/ipv4: ... |
995 |
if (ipv4_is_multicast(p.iph.daddr)) |
1da177e4c Linux-2.6.12-rc2 |
996 997 998 999 1000 1001 1002 1003 |
nflags = IFF_BROADCAST; else if (p.iph.daddr) nflags = IFF_POINTOPOINT; if ((dev->flags^nflags)&(IFF_POINTOPOINT|IFF_BROADCAST)) { err = -EINVAL; break; } |
f57e7d5a7 [GRE]: Add net/gr... |
1004 |
ipgre_tunnel_unlink(ign, t); |
74b0b85b8 tunnels: Fix tunn... |
1005 |
synchronize_net(); |
1da177e4c Linux-2.6.12-rc2 |
1006 1007 1008 1009 1010 1011 |
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; memcpy(dev->dev_addr, &p.iph.saddr, 4); memcpy(dev->broadcast, &p.iph.daddr, 4); |
f57e7d5a7 [GRE]: Add net/gr... |
1012 |
ipgre_tunnel_link(ign, t); |
1da177e4c Linux-2.6.12-rc2 |
1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 |
netdev_state_change(dev); } } if (t) { err = 0; if (cmd == SIOCCHGTUNNEL) { t->parms.iph.ttl = p.iph.ttl; t->parms.iph.tos = p.iph.tos; t->parms.iph.frag_off = p.iph.frag_off; |
ee34c1eb3 [IP_GRE]: Rebindi... |
1023 1024 |
if (t->parms.link != p.link) { t->parms.link = p.link; |
42aa91626 gre: Move MTU set... |
1025 |
dev->mtu = ipgre_tunnel_bind_dev(dev); |
ee34c1eb3 [IP_GRE]: Rebindi... |
1026 1027 |
netdev_state_change(dev); } |
1da177e4c Linux-2.6.12-rc2 |
1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 |
} if (copy_to_user(ifr->ifr_ifru.ifru_data, &t->parms, sizeof(p))) err = -EFAULT; } else err = (cmd == SIOCADDTUNNEL ? -ENOBUFS : -ENOENT); break; case SIOCDELTUNNEL: err = -EPERM; if (!capable(CAP_NET_ADMIN)) goto done; |
7daa00048 [GRE]: Make the f... |
1039 |
if (dev == ign->fb_tunnel_dev) { |
1da177e4c Linux-2.6.12-rc2 |
1040 1041 1042 1043 |
err = -EFAULT; if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) goto done; err = -ENOENT; |
f57e7d5a7 [GRE]: Add net/gr... |
1044 |
if ((t = ipgre_tunnel_locate(net, &p, 0)) == NULL) |
1da177e4c Linux-2.6.12-rc2 |
1045 1046 |
goto done; err = -EPERM; |
7daa00048 [GRE]: Make the f... |
1047 |
if (t == netdev_priv(ign->fb_tunnel_dev)) |
1da177e4c Linux-2.6.12-rc2 |
1048 1049 1050 |
goto done; dev = t->dev; } |
22f8cde5b [NET]: unregister... |
1051 1052 |
unregister_netdevice(dev); err = 0; |
1da177e4c Linux-2.6.12-rc2 |
1053 1054 1055 1056 1057 1058 1059 1060 1061 |
break; default: err = -EINVAL; } done: return err; } |
1da177e4c Linux-2.6.12-rc2 |
1062 1063 |
static int ipgre_tunnel_change_mtu(struct net_device *dev, int new_mtu) { |
2941a4863 [NET]: Convert ne... |
1064 |
struct ip_tunnel *tunnel = netdev_priv(dev); |
c95b819ad gre: Use needed_h... |
1065 1066 |
if (new_mtu < 68 || new_mtu > 0xFFF8 - dev->hard_header_len - tunnel->hlen) |
1da177e4c Linux-2.6.12-rc2 |
1067 1068 1069 1070 |
return -EINVAL; dev->mtu = new_mtu; return 0; } |
1da177e4c Linux-2.6.12-rc2 |
1071 1072 1073 1074 1075 1076 1077 1078 1079 |
/* Nice toy. Unfortunately, useless in real life :-) It allows to construct virtual multiprotocol broadcast "LAN" over the Internet, provided multicast routing is tuned. I have no idea was this bicycle invented before me, so that I had to set ARPHRD_IPGRE to a random value. I have an impression, that Cisco could make something similar, but this feature is apparently missing in IOS<=11.2(8). |
e905a9eda [NET] IPV4: Fix w... |
1080 |
|
1da177e4c Linux-2.6.12-rc2 |
1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 |
I set up 10.66.66/24 and fec0:6666:6666::0/96 as virtual networks with broadcast 224.66.66.66. If you have access to mbone, play with me :-) ping -t 255 224.66.66.66 If nobody answers, mbone does not work. ip tunnel add Universe mode gre remote 224.66.66.66 local <Your_real_addr> ttl 255 ip addr add 10.66.66.<somewhat>/24 dev Universe ifconfig Universe up ifconfig Universe add fe80::<Your_real_addr>/10 ifconfig Universe add fec0:6666:6666::<Your_real_addr>/96 ftp 10.66.66.66 ... ftp fec0:6666:6666::193.233.7.65 ... */ |
3b04ddde0 [NET]: Move hardw... |
1099 1100 |
static int ipgre_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, |
1507850b4 gre: get rid of i... |
1101 |
const void *daddr, const void *saddr, unsigned int len) |
1da177e4c Linux-2.6.12-rc2 |
1102 |
{ |
2941a4863 [NET]: Convert ne... |
1103 |
struct ip_tunnel *t = netdev_priv(dev); |
1da177e4c Linux-2.6.12-rc2 |
1104 |
struct iphdr *iph = (struct iphdr *)skb_push(skb, t->hlen); |
d5a0a1e31 [IPV4]: encapsula... |
1105 |
__be16 *p = (__be16*)(iph+1); |
1da177e4c Linux-2.6.12-rc2 |
1106 1107 1108 1109 1110 1111 |
memcpy(iph, &t->parms.iph, sizeof(struct iphdr)); p[0] = t->parms.o_flags; p[1] = htons(type); /* |
e905a9eda [NET] IPV4: Fix w... |
1112 |
* Set the source hardware address. |
1da177e4c Linux-2.6.12-rc2 |
1113 |
*/ |
e905a9eda [NET] IPV4: Fix w... |
1114 |
|
1da177e4c Linux-2.6.12-rc2 |
1115 1116 |
if (saddr) memcpy(&iph->saddr, saddr, 4); |
6d55cb91a gre: fix hard hea... |
1117 |
if (daddr) |
1da177e4c Linux-2.6.12-rc2 |
1118 |
memcpy(&iph->daddr, daddr, 4); |
6d55cb91a gre: fix hard hea... |
1119 |
if (iph->daddr) |
1da177e4c Linux-2.6.12-rc2 |
1120 |
return t->hlen; |
e905a9eda [NET] IPV4: Fix w... |
1121 |
|
1da177e4c Linux-2.6.12-rc2 |
1122 1123 |
return -t->hlen; } |
6a5f44d7a [IPV4] ip_gre: se... |
1124 1125 |
static int ipgre_header_parse(const struct sk_buff *skb, unsigned char *haddr) { |
b71d1d426 inet: constify ip... |
1126 |
const struct iphdr *iph = (const struct iphdr *) skb_mac_header(skb); |
6a5f44d7a [IPV4] ip_gre: se... |
1127 1128 1129 |
memcpy(haddr, &iph->saddr, 4); return 4; } |
3b04ddde0 [NET]: Move hardw... |
1130 1131 |
static const struct header_ops ipgre_header_ops = { .create = ipgre_header, |
6a5f44d7a [IPV4] ip_gre: se... |
1132 |
.parse = ipgre_header_parse, |
3b04ddde0 [NET]: Move hardw... |
1133 |
}; |
6a5f44d7a [IPV4] ip_gre: se... |
1134 |
#ifdef CONFIG_NET_IPGRE_BROADCAST |
1da177e4c Linux-2.6.12-rc2 |
1135 1136 |
static int ipgre_open(struct net_device *dev) { |
2941a4863 [NET]: Convert ne... |
1137 |
struct ip_tunnel *t = netdev_priv(dev); |
1da177e4c Linux-2.6.12-rc2 |
1138 |
|
f97c1e0c6 [IPV4] net/ipv4: ... |
1139 |
if (ipv4_is_multicast(t->parms.iph.daddr)) { |
cbb1e85f9 ipv4: Kill rt->rt... |
1140 1141 1142 1143 1144 1145 1146 1147 1148 |
struct flowi4 fl4; struct rtable *rt; rt = ip_route_output_gre(dev_net(dev), &fl4, t->parms.iph.daddr, t->parms.iph.saddr, t->parms.o_key, RT_TOS(t->parms.iph.tos), t->parms.link); |
b23dd4fe4 ipv4: Make output... |
1149 |
if (IS_ERR(rt)) |
1da177e4c Linux-2.6.12-rc2 |
1150 |
return -EADDRNOTAVAIL; |
d8d1f30b9 net-next: remove ... |
1151 |
dev = rt->dst.dev; |
1da177e4c Linux-2.6.12-rc2 |
1152 |
ip_rt_put(rt); |
e5ed63991 [IPV4]: Replace _... |
1153 |
if (__in_dev_get_rtnl(dev) == NULL) |
1da177e4c Linux-2.6.12-rc2 |
1154 1155 |
return -EADDRNOTAVAIL; t->mlink = dev->ifindex; |
e5ed63991 [IPV4]: Replace _... |
1156 |
ip_mc_inc_group(__in_dev_get_rtnl(dev), t->parms.iph.daddr); |
1da177e4c Linux-2.6.12-rc2 |
1157 1158 1159 1160 1161 1162 |
} return 0; } static int ipgre_close(struct net_device *dev) { |
2941a4863 [NET]: Convert ne... |
1163 |
struct ip_tunnel *t = netdev_priv(dev); |
b8c26a33c ipgre: convert to... |
1164 |
|
f97c1e0c6 [IPV4] net/ipv4: ... |
1165 |
if (ipv4_is_multicast(t->parms.iph.daddr) && t->mlink) { |
7fee0ca23 [NETNS]: Add netn... |
1166 |
struct in_device *in_dev; |
c346dca10 [NET] NETNS: Omit... |
1167 |
in_dev = inetdev_by_index(dev_net(dev), t->mlink); |
8723e1b4a inet: RCU changes... |
1168 |
if (in_dev) |
1da177e4c Linux-2.6.12-rc2 |
1169 |
ip_mc_dec_group(in_dev, t->parms.iph.daddr); |
1da177e4c Linux-2.6.12-rc2 |
1170 1171 1172 1173 1174 |
} return 0; } #endif |
b8c26a33c ipgre: convert to... |
1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 |
static const struct net_device_ops ipgre_netdev_ops = { .ndo_init = ipgre_tunnel_init, .ndo_uninit = ipgre_tunnel_uninit, #ifdef CONFIG_NET_IPGRE_BROADCAST .ndo_open = ipgre_open, .ndo_stop = ipgre_close, #endif .ndo_start_xmit = ipgre_tunnel_xmit, .ndo_do_ioctl = ipgre_tunnel_ioctl, .ndo_change_mtu = ipgre_tunnel_change_mtu, |
e985aad72 ip_gre: percpu st... |
1185 |
.ndo_get_stats = ipgre_get_stats, |
b8c26a33c ipgre: convert to... |
1186 |
}; |
e985aad72 ip_gre: percpu st... |
1187 1188 1189 1190 1191 |
static void ipgre_dev_free(struct net_device *dev) { free_percpu(dev->tstats); free_netdev(dev); } |
1da177e4c Linux-2.6.12-rc2 |
1192 1193 |
static void ipgre_tunnel_setup(struct net_device *dev) { |
b8c26a33c ipgre: convert to... |
1194 |
dev->netdev_ops = &ipgre_netdev_ops; |
e985aad72 ip_gre: percpu st... |
1195 |
dev->destructor = ipgre_dev_free; |
1da177e4c Linux-2.6.12-rc2 |
1196 1197 |
dev->type = ARPHRD_IPGRE; |
c95b819ad gre: Use needed_h... |
1198 |
dev->needed_headroom = LL_MAX_HEADER + sizeof(struct iphdr) + 4; |
46f25dffb [NET]: Change 150... |
1199 |
dev->mtu = ETH_DATA_LEN - sizeof(struct iphdr) - 4; |
1da177e4c Linux-2.6.12-rc2 |
1200 1201 1202 |
dev->flags = IFF_NOARP; dev->iflink = 0; dev->addr_len = 4; |
0b67eceb1 [GRE]: Allow to c... |
1203 |
dev->features |= NETIF_F_NETNS_LOCAL; |
108bfa895 net: unset IFF_XM... |
1204 |
dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; |
1da177e4c Linux-2.6.12-rc2 |
1205 1206 1207 1208 |
} static int ipgre_tunnel_init(struct net_device *dev) { |
1da177e4c Linux-2.6.12-rc2 |
1209 1210 |
struct ip_tunnel *tunnel; struct iphdr *iph; |
1da177e4c Linux-2.6.12-rc2 |
1211 |
|
2941a4863 [NET]: Convert ne... |
1212 |
tunnel = netdev_priv(dev); |
1da177e4c Linux-2.6.12-rc2 |
1213 1214 1215 1216 1217 1218 1219 |
iph = &tunnel->parms.iph; tunnel->dev = dev; strcpy(tunnel->parms.name, dev->name); memcpy(dev->dev_addr, &tunnel->parms.iph.saddr, 4); memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4); |
1da177e4c Linux-2.6.12-rc2 |
1220 |
if (iph->daddr) { |
1da177e4c Linux-2.6.12-rc2 |
1221 |
#ifdef CONFIG_NET_IPGRE_BROADCAST |
f97c1e0c6 [IPV4] net/ipv4: ... |
1222 |
if (ipv4_is_multicast(iph->daddr)) { |
1da177e4c Linux-2.6.12-rc2 |
1223 1224 1225 |
if (!iph->saddr) return -EINVAL; dev->flags = IFF_BROADCAST; |
3b04ddde0 [NET]: Move hardw... |
1226 |
dev->header_ops = &ipgre_header_ops; |
1da177e4c Linux-2.6.12-rc2 |
1227 1228 |
} #endif |
ee34c1eb3 [IP_GRE]: Rebindi... |
1229 |
} else |
6a5f44d7a [IPV4] ip_gre: se... |
1230 |
dev->header_ops = &ipgre_header_ops; |
1da177e4c Linux-2.6.12-rc2 |
1231 |
|
e985aad72 ip_gre: percpu st... |
1232 1233 1234 |
dev->tstats = alloc_percpu(struct pcpu_tstats); if (!dev->tstats) return -ENOMEM; |
1da177e4c Linux-2.6.12-rc2 |
1235 1236 |
return 0; } |
b8c26a33c ipgre: convert to... |
1237 |
static void ipgre_fb_tunnel_init(struct net_device *dev) |
1da177e4c Linux-2.6.12-rc2 |
1238 |
{ |
2941a4863 [NET]: Convert ne... |
1239 |
struct ip_tunnel *tunnel = netdev_priv(dev); |
1da177e4c Linux-2.6.12-rc2 |
1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 |
struct iphdr *iph = &tunnel->parms.iph; tunnel->dev = dev; strcpy(tunnel->parms.name, dev->name); iph->version = 4; iph->protocol = IPPROTO_GRE; iph->ihl = 5; tunnel->hlen = sizeof(struct iphdr) + 4; dev_hold(dev); |
1da177e4c Linux-2.6.12-rc2 |
1251 |
} |
00959ade3 PPTP: PPP over IP... |
1252 1253 1254 |
static const struct gre_protocol ipgre_protocol = { .handler = ipgre_rcv, .err_handler = ipgre_err, |
1da177e4c Linux-2.6.12-rc2 |
1255 |
}; |
eef6dd65e gre: Optimize mul... |
1256 |
static void ipgre_destroy_tunnels(struct ipgre_net *ign, struct list_head *head) |
eb8ce741a [GRE]: Make tunne... |
1257 1258 1259 1260 1261 1262 |
{ int prio; for (prio = 0; prio < 4; prio++) { int h; for (h = 0; h < HASH_SIZE; h++) { |
1507850b4 gre: get rid of i... |
1263 1264 1265 |
struct ip_tunnel *t; t = rtnl_dereference(ign->tunnels[prio][h]); |
eef6dd65e gre: Optimize mul... |
1266 1267 1268 |
while (t != NULL) { unregister_netdevice_queue(t->dev, head); |
1507850b4 gre: get rid of i... |
1269 |
t = rtnl_dereference(t->next); |
eef6dd65e gre: Optimize mul... |
1270 |
} |
eb8ce741a [GRE]: Make tunne... |
1271 1272 1273 |
} } } |
2c8c1e729 net: spread __net... |
1274 |
static int __net_init ipgre_init_net(struct net *net) |
59a4c7594 [GRE]: Introduce ... |
1275 |
{ |
cfb8fbf22 net: Simplify ip_... |
1276 |
struct ipgre_net *ign = net_generic(net, ipgre_net_id); |
59a4c7594 [GRE]: Introduce ... |
1277 |
int err; |
59a4c7594 [GRE]: Introduce ... |
1278 |
|
7daa00048 [GRE]: Make the f... |
1279 1280 1281 1282 1283 1284 |
ign->fb_tunnel_dev = alloc_netdev(sizeof(struct ip_tunnel), "gre0", ipgre_tunnel_setup); if (!ign->fb_tunnel_dev) { err = -ENOMEM; goto err_alloc_dev; } |
be77e5930 net: fix tunnels ... |
1285 |
dev_net_set(ign->fb_tunnel_dev, net); |
7daa00048 [GRE]: Make the f... |
1286 |
|
b8c26a33c ipgre: convert to... |
1287 |
ipgre_fb_tunnel_init(ign->fb_tunnel_dev); |
c19e654dd gre: Add netlink ... |
1288 |
ign->fb_tunnel_dev->rtnl_link_ops = &ipgre_link_ops; |
7daa00048 [GRE]: Make the f... |
1289 1290 1291 |
if ((err = register_netdev(ign->fb_tunnel_dev))) goto err_reg_dev; |
3285ee3bb ip_gre: fix fallb... |
1292 1293 |
rcu_assign_pointer(ign->tunnels_wc[0], netdev_priv(ign->fb_tunnel_dev)); |
59a4c7594 [GRE]: Introduce ... |
1294 |
return 0; |
7daa00048 [GRE]: Make the f... |
1295 |
err_reg_dev: |
3285ee3bb ip_gre: fix fallb... |
1296 |
ipgre_dev_free(ign->fb_tunnel_dev); |
7daa00048 [GRE]: Make the f... |
1297 |
err_alloc_dev: |
59a4c7594 [GRE]: Introduce ... |
1298 1299 |
return err; } |
2c8c1e729 net: spread __net... |
1300 |
static void __net_exit ipgre_exit_net(struct net *net) |
59a4c7594 [GRE]: Introduce ... |
1301 1302 |
{ struct ipgre_net *ign; |
eef6dd65e gre: Optimize mul... |
1303 |
LIST_HEAD(list); |
59a4c7594 [GRE]: Introduce ... |
1304 1305 |
ign = net_generic(net, ipgre_net_id); |
7daa00048 [GRE]: Make the f... |
1306 |
rtnl_lock(); |
eef6dd65e gre: Optimize mul... |
1307 1308 |
ipgre_destroy_tunnels(ign, &list); unregister_netdevice_many(&list); |
7daa00048 [GRE]: Make the f... |
1309 |
rtnl_unlock(); |
59a4c7594 [GRE]: Introduce ... |
1310 1311 1312 1313 1314 |
} static struct pernet_operations ipgre_net_ops = { .init = ipgre_init_net, .exit = ipgre_exit_net, |
cfb8fbf22 net: Simplify ip_... |
1315 1316 |
.id = &ipgre_net_id, .size = sizeof(struct ipgre_net), |
59a4c7594 [GRE]: Introduce ... |
1317 |
}; |
1da177e4c Linux-2.6.12-rc2 |
1318 |
|
c19e654dd gre: Add netlink ... |
1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 |
static int ipgre_tunnel_validate(struct nlattr *tb[], struct nlattr *data[]) { __be16 flags; if (!data) return 0; flags = 0; if (data[IFLA_GRE_IFLAGS]) flags |= nla_get_be16(data[IFLA_GRE_IFLAGS]); if (data[IFLA_GRE_OFLAGS]) flags |= nla_get_be16(data[IFLA_GRE_OFLAGS]); if (flags & (GRE_VERSION|GRE_ROUTING)) return -EINVAL; return 0; } |
e1a800022 gre: Add Transpar... |
1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 |
static int ipgre_tap_validate(struct nlattr *tb[], struct nlattr *data[]) { __be32 daddr; if (tb[IFLA_ADDRESS]) { if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN) return -EINVAL; if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS]))) return -EADDRNOTAVAIL; } if (!data) goto out; if (data[IFLA_GRE_REMOTE]) { memcpy(&daddr, nla_data(data[IFLA_GRE_REMOTE]), 4); if (!daddr) return -EINVAL; } out: return ipgre_tunnel_validate(tb, data); } |
c19e654dd gre: Add netlink ... |
1359 1360 1361 |
static void ipgre_netlink_parms(struct nlattr *data[], struct ip_tunnel_parm *parms) { |
7bb82d924 gre: Initialise r... |
1362 |
memset(parms, 0, sizeof(*parms)); |
c19e654dd gre: Add netlink ... |
1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 |
parms->iph.protocol = IPPROTO_GRE; if (!data) return; if (data[IFLA_GRE_LINK]) parms->link = nla_get_u32(data[IFLA_GRE_LINK]); if (data[IFLA_GRE_IFLAGS]) parms->i_flags = nla_get_be16(data[IFLA_GRE_IFLAGS]); if (data[IFLA_GRE_OFLAGS]) parms->o_flags = nla_get_be16(data[IFLA_GRE_OFLAGS]); if (data[IFLA_GRE_IKEY]) parms->i_key = nla_get_be32(data[IFLA_GRE_IKEY]); if (data[IFLA_GRE_OKEY]) parms->o_key = nla_get_be32(data[IFLA_GRE_OKEY]); if (data[IFLA_GRE_LOCAL]) |
4d74f8ba1 gre: minor cleanu... |
1385 |
parms->iph.saddr = nla_get_be32(data[IFLA_GRE_LOCAL]); |
c19e654dd gre: Add netlink ... |
1386 1387 |
if (data[IFLA_GRE_REMOTE]) |
4d74f8ba1 gre: minor cleanu... |
1388 |
parms->iph.daddr = nla_get_be32(data[IFLA_GRE_REMOTE]); |
c19e654dd gre: Add netlink ... |
1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 |
if (data[IFLA_GRE_TTL]) parms->iph.ttl = nla_get_u8(data[IFLA_GRE_TTL]); if (data[IFLA_GRE_TOS]) parms->iph.tos = nla_get_u8(data[IFLA_GRE_TOS]); if (!data[IFLA_GRE_PMTUDISC] || nla_get_u8(data[IFLA_GRE_PMTUDISC])) parms->iph.frag_off = htons(IP_DF); } |
e1a800022 gre: Add Transpar... |
1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 |
static int ipgre_tap_init(struct net_device *dev) { struct ip_tunnel *tunnel; tunnel = netdev_priv(dev); tunnel->dev = dev; strcpy(tunnel->parms.name, dev->name); ipgre_tunnel_bind_dev(dev); |
e985aad72 ip_gre: percpu st... |
1409 1410 1411 |
dev->tstats = alloc_percpu(struct pcpu_tstats); if (!dev->tstats) return -ENOMEM; |
e1a800022 gre: Add Transpar... |
1412 1413 |
return 0; } |
b8c26a33c ipgre: convert to... |
1414 1415 1416 1417 1418 1419 1420 |
static const struct net_device_ops ipgre_tap_netdev_ops = { .ndo_init = ipgre_tap_init, .ndo_uninit = ipgre_tunnel_uninit, .ndo_start_xmit = ipgre_tunnel_xmit, .ndo_set_mac_address = eth_mac_addr, .ndo_validate_addr = eth_validate_addr, .ndo_change_mtu = ipgre_tunnel_change_mtu, |
e985aad72 ip_gre: percpu st... |
1421 |
.ndo_get_stats = ipgre_get_stats, |
b8c26a33c ipgre: convert to... |
1422 |
}; |
e1a800022 gre: Add Transpar... |
1423 1424 1425 1426 |
static void ipgre_tap_setup(struct net_device *dev) { ether_setup(dev); |
2e9526b35 gre: Fix dev_addr... |
1427 |
dev->netdev_ops = &ipgre_tap_netdev_ops; |
e985aad72 ip_gre: percpu st... |
1428 |
dev->destructor = ipgre_dev_free; |
e1a800022 gre: Add Transpar... |
1429 1430 1431 1432 |
dev->iflink = 0; dev->features |= NETIF_F_NETNS_LOCAL; } |
81adee47d net: Support spec... |
1433 |
static int ipgre_newlink(struct net *src_net, struct net_device *dev, struct nlattr *tb[], |
c19e654dd gre: Add netlink ... |
1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 |
struct nlattr *data[]) { struct ip_tunnel *nt; struct net *net = dev_net(dev); struct ipgre_net *ign = net_generic(net, ipgre_net_id); int mtu; int err; nt = netdev_priv(dev); ipgre_netlink_parms(data, &nt->parms); |
e1a800022 gre: Add Transpar... |
1444 |
if (ipgre_tunnel_find(net, &nt->parms, dev->type)) |
c19e654dd gre: Add netlink ... |
1445 |
return -EEXIST; |
e1a800022 gre: Add Transpar... |
1446 1447 |
if (dev->type == ARPHRD_ETHER && !tb[IFLA_ADDRESS]) random_ether_addr(dev->dev_addr); |
c19e654dd gre: Add netlink ... |
1448 1449 1450 |
mtu = ipgre_tunnel_bind_dev(dev); if (!tb[IFLA_MTU]) dev->mtu = mtu; |
b790e01ae ip_gre: lockless ... |
1451 1452 1453 |
/* Can use a lockless transmit, unless we generate output sequences */ if (!(nt->parms.o_flags & GRE_SEQ)) dev->features |= NETIF_F_LLTX; |
c19e654dd gre: Add netlink ... |
1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 |
err = register_netdevice(dev); if (err) goto out; dev_hold(dev); ipgre_tunnel_link(ign, nt); out: return err; } static int ipgre_changelink(struct net_device *dev, struct nlattr *tb[], struct nlattr *data[]) { struct ip_tunnel *t, *nt; struct net *net = dev_net(dev); struct ipgre_net *ign = net_generic(net, ipgre_net_id); struct ip_tunnel_parm p; int mtu; if (dev == ign->fb_tunnel_dev) return -EINVAL; nt = netdev_priv(dev); ipgre_netlink_parms(data, &p); t = ipgre_tunnel_locate(net, &p, 0); if (t) { if (t->dev != dev) return -EEXIST; } else { |
c19e654dd gre: Add netlink ... |
1486 |
t = nt; |
2e9526b35 gre: Fix dev_addr... |
1487 |
if (dev->type != ARPHRD_ETHER) { |
1507850b4 gre: get rid of i... |
1488 |
unsigned int nflags = 0; |
c19e654dd gre: Add netlink ... |
1489 |
|
2e9526b35 gre: Fix dev_addr... |
1490 1491 1492 1493 1494 1495 1496 1497 1498 |
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; } |
c19e654dd gre: Add netlink ... |
1499 1500 1501 1502 1503 |
ipgre_tunnel_unlink(ign, t); t->parms.iph.saddr = p.iph.saddr; t->parms.iph.daddr = p.iph.daddr; t->parms.i_key = p.i_key; |
2e9526b35 gre: Fix dev_addr... |
1504 1505 1506 1507 |
if (dev->type != ARPHRD_ETHER) { memcpy(dev->dev_addr, &p.iph.saddr, 4); memcpy(dev->broadcast, &p.iph.daddr, 4); } |
c19e654dd gre: Add netlink ... |
1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 |
ipgre_tunnel_link(ign, t); netdev_state_change(dev); } t->parms.o_key = p.o_key; t->parms.iph.ttl = p.iph.ttl; t->parms.iph.tos = p.iph.tos; t->parms.iph.frag_off = p.iph.frag_off; if (t->parms.link != p.link) { t->parms.link = p.link; mtu = ipgre_tunnel_bind_dev(dev); if (!tb[IFLA_MTU]) dev->mtu = mtu; netdev_state_change(dev); } return 0; } static size_t ipgre_get_size(const struct net_device *dev) { return /* IFLA_GRE_LINK */ nla_total_size(4) + /* IFLA_GRE_IFLAGS */ nla_total_size(2) + /* IFLA_GRE_OFLAGS */ nla_total_size(2) + /* IFLA_GRE_IKEY */ nla_total_size(4) + /* IFLA_GRE_OKEY */ nla_total_size(4) + /* IFLA_GRE_LOCAL */ nla_total_size(4) + /* IFLA_GRE_REMOTE */ nla_total_size(4) + /* IFLA_GRE_TTL */ nla_total_size(1) + /* IFLA_GRE_TOS */ nla_total_size(1) + /* IFLA_GRE_PMTUDISC */ nla_total_size(1) + 0; } static int ipgre_fill_info(struct sk_buff *skb, const struct net_device *dev) { struct ip_tunnel *t = netdev_priv(dev); struct ip_tunnel_parm *p = &t->parms; NLA_PUT_U32(skb, IFLA_GRE_LINK, p->link); NLA_PUT_BE16(skb, IFLA_GRE_IFLAGS, p->i_flags); NLA_PUT_BE16(skb, IFLA_GRE_OFLAGS, p->o_flags); |
ba9e64b1c gre: fix copy and... |
1562 1563 |
NLA_PUT_BE32(skb, IFLA_GRE_IKEY, p->i_key); NLA_PUT_BE32(skb, IFLA_GRE_OKEY, p->o_key); |
4d74f8ba1 gre: minor cleanu... |
1564 1565 |
NLA_PUT_BE32(skb, IFLA_GRE_LOCAL, p->iph.saddr); NLA_PUT_BE32(skb, IFLA_GRE_REMOTE, p->iph.daddr); |
c19e654dd gre: Add netlink ... |
1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 |
NLA_PUT_U8(skb, IFLA_GRE_TTL, p->iph.ttl); NLA_PUT_U8(skb, IFLA_GRE_TOS, p->iph.tos); NLA_PUT_U8(skb, IFLA_GRE_PMTUDISC, !!(p->iph.frag_off & htons(IP_DF))); return 0; nla_put_failure: return -EMSGSIZE; } static const struct nla_policy ipgre_policy[IFLA_GRE_MAX + 1] = { [IFLA_GRE_LINK] = { .type = NLA_U32 }, [IFLA_GRE_IFLAGS] = { .type = NLA_U16 }, [IFLA_GRE_OFLAGS] = { .type = NLA_U16 }, [IFLA_GRE_IKEY] = { .type = NLA_U32 }, [IFLA_GRE_OKEY] = { .type = NLA_U32 }, |
4d74f8ba1 gre: minor cleanu... |
1582 1583 |
[IFLA_GRE_LOCAL] = { .len = FIELD_SIZEOF(struct iphdr, saddr) }, [IFLA_GRE_REMOTE] = { .len = FIELD_SIZEOF(struct iphdr, daddr) }, |
c19e654dd gre: Add netlink ... |
1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 |
[IFLA_GRE_TTL] = { .type = NLA_U8 }, [IFLA_GRE_TOS] = { .type = NLA_U8 }, [IFLA_GRE_PMTUDISC] = { .type = NLA_U8 }, }; static struct rtnl_link_ops ipgre_link_ops __read_mostly = { .kind = "gre", .maxtype = IFLA_GRE_MAX, .policy = ipgre_policy, .priv_size = sizeof(struct ip_tunnel), .setup = ipgre_tunnel_setup, .validate = ipgre_tunnel_validate, .newlink = ipgre_newlink, .changelink = ipgre_changelink, .get_size = ipgre_get_size, .fill_info = ipgre_fill_info, }; |
e1a800022 gre: Add Transpar... |
1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 |
static struct rtnl_link_ops ipgre_tap_ops __read_mostly = { .kind = "gretap", .maxtype = IFLA_GRE_MAX, .policy = ipgre_policy, .priv_size = sizeof(struct ip_tunnel), .setup = ipgre_tap_setup, .validate = ipgre_tap_validate, .newlink = ipgre_newlink, .changelink = ipgre_changelink, .get_size = ipgre_get_size, .fill_info = ipgre_fill_info, }; |
1da177e4c Linux-2.6.12-rc2 |
1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 |
/* * And now the modules code and kernel interface. */ static int __init ipgre_init(void) { int err; printk(KERN_INFO "GRE over IPv4 tunneling driver "); |
cfb8fbf22 net: Simplify ip_... |
1623 |
err = register_pernet_device(&ipgre_net_ops); |
59a4c7594 [GRE]: Introduce ... |
1624 |
if (err < 0) |
c2892f027 gre: fix netns vs... |
1625 |
return err; |
00959ade3 PPTP: PPP over IP... |
1626 |
err = gre_add_protocol(&ipgre_protocol, GREPROTO_CISCO); |
c2892f027 gre: fix netns vs... |
1627 1628 1629 1630 1631 |
if (err < 0) { printk(KERN_INFO "ipgre init: can't add protocol "); goto add_proto_failed; } |
7daa00048 [GRE]: Make the f... |
1632 |
|
c19e654dd gre: Add netlink ... |
1633 1634 1635 |
err = rtnl_link_register(&ipgre_link_ops); if (err < 0) goto rtnl_link_failed; |
e1a800022 gre: Add Transpar... |
1636 1637 1638 |
err = rtnl_link_register(&ipgre_tap_ops); if (err < 0) goto tap_ops_failed; |
c19e654dd gre: Add netlink ... |
1639 |
out: |
1da177e4c Linux-2.6.12-rc2 |
1640 |
return err; |
c19e654dd gre: Add netlink ... |
1641 |
|
e1a800022 gre: Add Transpar... |
1642 1643 |
tap_ops_failed: rtnl_link_unregister(&ipgre_link_ops); |
c19e654dd gre: Add netlink ... |
1644 |
rtnl_link_failed: |
00959ade3 PPTP: PPP over IP... |
1645 |
gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO); |
c2892f027 gre: fix netns vs... |
1646 1647 |
add_proto_failed: unregister_pernet_device(&ipgre_net_ops); |
c19e654dd gre: Add netlink ... |
1648 |
goto out; |
1da177e4c Linux-2.6.12-rc2 |
1649 |
} |
db44575f6 [NET]: fix oops a... |
1650 |
static void __exit ipgre_fini(void) |
1da177e4c Linux-2.6.12-rc2 |
1651 |
{ |
e1a800022 gre: Add Transpar... |
1652 |
rtnl_link_unregister(&ipgre_tap_ops); |
c19e654dd gre: Add netlink ... |
1653 |
rtnl_link_unregister(&ipgre_link_ops); |
00959ade3 PPTP: PPP over IP... |
1654 |
if (gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO) < 0) |
1da177e4c Linux-2.6.12-rc2 |
1655 1656 |
printk(KERN_INFO "ipgre close: can't remove protocol "); |
c2892f027 gre: fix netns vs... |
1657 |
unregister_pernet_device(&ipgre_net_ops); |
1da177e4c Linux-2.6.12-rc2 |
1658 1659 1660 1661 1662 |
} module_init(ipgre_init); module_exit(ipgre_fini); MODULE_LICENSE("GPL"); |
4d74f8ba1 gre: minor cleanu... |
1663 1664 |
MODULE_ALIAS_RTNL_LINK("gre"); MODULE_ALIAS_RTNL_LINK("gretap"); |
8909c9ad8 net: don't allow ... |
1665 |
MODULE_ALIAS_NETDEV("gre0"); |