diff options
author | Amerigo Wang <amwang@redhat.com> | 2013-07-20 22:46:25 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-07-23 20:27:32 -0400 |
commit | b9959fd3b0fa8ee5f45012ae5258d87ee6852baa (patch) | |
tree | 541d67a444cbc9f5ab491dc2d5b0de40aaed0500 /net | |
parent | 2b52c3ada8f4391d82d8088d9169ac2a8c4d0411 (diff) |
vti: switch to new ip tunnel code
GRE tunnel and IPIP tunnel already switched to the new
ip tunnel code, VTI tunnel can use it too.
Cc: Pravin B Shelar <pshelar@nicira.com>
Cc: Stephen Hemminger <stephen@networkplumber.org>
Cc: Saurabh Mohan <saurabh.mohan@vyatta.com>
Cc: "David S. Miller" <davem@davemloft.net>
Signed-off-by: Cong Wang <amwang@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv4/ip_vti.c | 528 |
1 files changed, 52 insertions, 476 deletions
diff --git a/net/ipv4/ip_vti.c b/net/ipv4/ip_vti.c index 17cc0ffa8c0d..79b263da4168 100644 --- a/net/ipv4/ip_vti.c +++ b/net/ipv4/ip_vti.c | |||
@@ -44,176 +44,10 @@ | |||
44 | #include <net/net_namespace.h> | 44 | #include <net/net_namespace.h> |
45 | #include <net/netns/generic.h> | 45 | #include <net/netns/generic.h> |
46 | 46 | ||
47 | #define HASH_SIZE 16 | ||
48 | #define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&(HASH_SIZE-1)) | ||
49 | |||
50 | static struct rtnl_link_ops vti_link_ops __read_mostly; | 47 | static struct rtnl_link_ops vti_link_ops __read_mostly; |
51 | 48 | ||
52 | static int vti_net_id __read_mostly; | 49 | static int vti_net_id __read_mostly; |
53 | struct vti_net { | ||
54 | struct ip_tunnel __rcu *tunnels_r_l[HASH_SIZE]; | ||
55 | struct ip_tunnel __rcu *tunnels_r[HASH_SIZE]; | ||
56 | struct ip_tunnel __rcu *tunnels_l[HASH_SIZE]; | ||
57 | struct ip_tunnel __rcu *tunnels_wc[1]; | ||
58 | struct ip_tunnel __rcu **tunnels[4]; | ||
59 | |||
60 | struct net_device *fb_tunnel_dev; | ||
61 | }; | ||
62 | |||
63 | static int vti_fb_tunnel_init(struct net_device *dev); | ||
64 | static int vti_tunnel_init(struct net_device *dev); | 50 | static int vti_tunnel_init(struct net_device *dev); |
65 | static void vti_tunnel_setup(struct net_device *dev); | ||
66 | static void vti_dev_free(struct net_device *dev); | ||
67 | static int vti_tunnel_bind_dev(struct net_device *dev); | ||
68 | |||
69 | #define VTI_XMIT(stats1, stats2) do { \ | ||
70 | int err; \ | ||
71 | int pkt_len = skb->len; \ | ||
72 | err = dst_output(skb); \ | ||
73 | if (net_xmit_eval(err) == 0) { \ | ||
74 | u64_stats_update_begin(&(stats1)->syncp); \ | ||
75 | (stats1)->tx_bytes += pkt_len; \ | ||
76 | (stats1)->tx_packets++; \ | ||
77 | u64_stats_update_end(&(stats1)->syncp); \ | ||
78 | } else { \ | ||
79 | (stats2)->tx_errors++; \ | ||
80 | (stats2)->tx_aborted_errors++; \ | ||
81 | } \ | ||
82 | } while (0) | ||
83 | |||
84 | |||
85 | static struct ip_tunnel *vti_tunnel_lookup(struct net *net, | ||
86 | __be32 remote, __be32 local) | ||
87 | { | ||
88 | unsigned h0 = HASH(remote); | ||
89 | unsigned h1 = HASH(local); | ||
90 | struct ip_tunnel *t; | ||
91 | struct vti_net *ipn = net_generic(net, vti_net_id); | ||
92 | |||
93 | for_each_ip_tunnel_rcu(t, ipn->tunnels_r_l[h0 ^ h1]) | ||
94 | if (local == t->parms.iph.saddr && | ||
95 | remote == t->parms.iph.daddr && (t->dev->flags&IFF_UP)) | ||
96 | return t; | ||
97 | for_each_ip_tunnel_rcu(t, ipn->tunnels_r[h0]) | ||
98 | if (remote == t->parms.iph.daddr && (t->dev->flags&IFF_UP)) | ||
99 | return t; | ||
100 | |||
101 | for_each_ip_tunnel_rcu(t, ipn->tunnels_l[h1]) | ||
102 | if (local == t->parms.iph.saddr && (t->dev->flags&IFF_UP)) | ||
103 | return t; | ||
104 | |||
105 | for_each_ip_tunnel_rcu(t, ipn->tunnels_wc[0]) | ||
106 | if (t && (t->dev->flags&IFF_UP)) | ||
107 | return t; | ||
108 | return NULL; | ||
109 | } | ||
110 | |||
111 | static struct ip_tunnel __rcu **__vti_bucket(struct vti_net *ipn, | ||
112 | struct ip_tunnel_parm *parms) | ||
113 | { | ||
114 | __be32 remote = parms->iph.daddr; | ||
115 | __be32 local = parms->iph.saddr; | ||
116 | unsigned h = 0; | ||
117 | int prio = 0; | ||
118 | |||
119 | if (remote) { | ||
120 | prio |= 2; | ||
121 | h ^= HASH(remote); | ||
122 | } | ||
123 | if (local) { | ||
124 | prio |= 1; | ||
125 | h ^= HASH(local); | ||
126 | } | ||
127 | return &ipn->tunnels[prio][h]; | ||
128 | } | ||
129 | |||
130 | static inline struct ip_tunnel __rcu **vti_bucket(struct vti_net *ipn, | ||
131 | struct ip_tunnel *t) | ||
132 | { | ||
133 | return __vti_bucket(ipn, &t->parms); | ||
134 | } | ||
135 | |||
136 | static void vti_tunnel_unlink(struct vti_net *ipn, struct ip_tunnel *t) | ||
137 | { | ||
138 | struct ip_tunnel __rcu **tp; | ||
139 | struct ip_tunnel *iter; | ||
140 | |||
141 | for (tp = vti_bucket(ipn, t); | ||
142 | (iter = rtnl_dereference(*tp)) != NULL; | ||
143 | tp = &iter->next) { | ||
144 | if (t == iter) { | ||
145 | rcu_assign_pointer(*tp, t->next); | ||
146 | break; | ||
147 | } | ||
148 | } | ||
149 | } | ||
150 | |||
151 | static void vti_tunnel_link(struct vti_net *ipn, struct ip_tunnel *t) | ||
152 | { | ||
153 | struct ip_tunnel __rcu **tp = vti_bucket(ipn, t); | ||
154 | |||
155 | rcu_assign_pointer(t->next, rtnl_dereference(*tp)); | ||
156 | rcu_assign_pointer(*tp, t); | ||
157 | } | ||
158 | |||
159 | static struct ip_tunnel *vti_tunnel_locate(struct net *net, | ||
160 | struct ip_tunnel_parm *parms, | ||
161 | int create) | ||
162 | { | ||
163 | __be32 remote = parms->iph.daddr; | ||
164 | __be32 local = parms->iph.saddr; | ||
165 | struct ip_tunnel *t, *nt; | ||
166 | struct ip_tunnel __rcu **tp; | ||
167 | struct net_device *dev; | ||
168 | char name[IFNAMSIZ]; | ||
169 | struct vti_net *ipn = net_generic(net, vti_net_id); | ||
170 | |||
171 | for (tp = __vti_bucket(ipn, parms); | ||
172 | (t = rtnl_dereference(*tp)) != NULL; | ||
173 | tp = &t->next) { | ||
174 | if (local == t->parms.iph.saddr && remote == t->parms.iph.daddr) | ||
175 | return t; | ||
176 | } | ||
177 | if (!create) | ||
178 | return NULL; | ||
179 | |||
180 | if (parms->name[0]) | ||
181 | strlcpy(name, parms->name, IFNAMSIZ); | ||
182 | else | ||
183 | strcpy(name, "vti%d"); | ||
184 | |||
185 | dev = alloc_netdev(sizeof(*t), name, vti_tunnel_setup); | ||
186 | if (dev == NULL) | ||
187 | return NULL; | ||
188 | |||
189 | dev_net_set(dev, net); | ||
190 | |||
191 | nt = netdev_priv(dev); | ||
192 | nt->parms = *parms; | ||
193 | dev->rtnl_link_ops = &vti_link_ops; | ||
194 | |||
195 | vti_tunnel_bind_dev(dev); | ||
196 | |||
197 | if (register_netdevice(dev) < 0) | ||
198 | goto failed_free; | ||
199 | |||
200 | dev_hold(dev); | ||
201 | vti_tunnel_link(ipn, nt); | ||
202 | return nt; | ||
203 | |||
204 | failed_free: | ||
205 | free_netdev(dev); | ||
206 | return NULL; | ||
207 | } | ||
208 | |||
209 | static void vti_tunnel_uninit(struct net_device *dev) | ||
210 | { | ||
211 | struct net *net = dev_net(dev); | ||
212 | struct vti_net *ipn = net_generic(net, vti_net_id); | ||
213 | |||
214 | vti_tunnel_unlink(ipn, netdev_priv(dev)); | ||
215 | dev_put(dev); | ||
216 | } | ||
217 | 51 | ||
218 | static int vti_err(struct sk_buff *skb, u32 info) | 52 | static int vti_err(struct sk_buff *skb, u32 info) |
219 | { | 53 | { |
@@ -222,6 +56,8 @@ static int vti_err(struct sk_buff *skb, u32 info) | |||
222 | * 8 bytes of packet payload. It means, that precise relaying of | 56 | * 8 bytes of packet payload. It means, that precise relaying of |
223 | * ICMP in the real Internet is absolutely infeasible. | 57 | * ICMP in the real Internet is absolutely infeasible. |
224 | */ | 58 | */ |
59 | struct net *net = dev_net(skb->dev); | ||
60 | struct ip_tunnel_net *itn = net_generic(net, vti_net_id); | ||
225 | struct iphdr *iph = (struct iphdr *)skb->data; | 61 | struct iphdr *iph = (struct iphdr *)skb->data; |
226 | const int type = icmp_hdr(skb)->type; | 62 | const int type = icmp_hdr(skb)->type; |
227 | const int code = icmp_hdr(skb)->code; | 63 | const int code = icmp_hdr(skb)->code; |
@@ -252,7 +88,8 @@ static int vti_err(struct sk_buff *skb, u32 info) | |||
252 | 88 | ||
253 | err = -ENOENT; | 89 | err = -ENOENT; |
254 | 90 | ||
255 | t = vti_tunnel_lookup(dev_net(skb->dev), iph->daddr, iph->saddr); | 91 | t = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY, |
92 | iph->daddr, iph->saddr, 0); | ||
256 | if (t == NULL) | 93 | if (t == NULL) |
257 | goto out; | 94 | goto out; |
258 | 95 | ||
@@ -281,8 +118,11 @@ static int vti_rcv(struct sk_buff *skb) | |||
281 | { | 118 | { |
282 | struct ip_tunnel *tunnel; | 119 | struct ip_tunnel *tunnel; |
283 | const struct iphdr *iph = ip_hdr(skb); | 120 | const struct iphdr *iph = ip_hdr(skb); |
121 | struct net *net = dev_net(skb->dev); | ||
122 | struct ip_tunnel_net *itn = net_generic(net, vti_net_id); | ||
284 | 123 | ||
285 | tunnel = vti_tunnel_lookup(dev_net(skb->dev), iph->saddr, iph->daddr); | 124 | tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY, |
125 | iph->saddr, iph->daddr, 0); | ||
286 | if (tunnel != NULL) { | 126 | if (tunnel != NULL) { |
287 | struct pcpu_tstats *tstats; | 127 | struct pcpu_tstats *tstats; |
288 | 128 | ||
@@ -311,7 +151,6 @@ static int vti_rcv(struct sk_buff *skb) | |||
311 | static netdev_tx_t vti_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) | 151 | static netdev_tx_t vti_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) |
312 | { | 152 | { |
313 | struct ip_tunnel *tunnel = netdev_priv(dev); | 153 | struct ip_tunnel *tunnel = netdev_priv(dev); |
314 | struct pcpu_tstats *tstats; | ||
315 | struct iphdr *tiph = &tunnel->parms.iph; | 154 | struct iphdr *tiph = &tunnel->parms.iph; |
316 | u8 tos; | 155 | u8 tos; |
317 | struct rtable *rt; /* Route to the other host */ | 156 | struct rtable *rt; /* Route to the other host */ |
@@ -319,6 +158,7 @@ static netdev_tx_t vti_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) | |||
319 | struct iphdr *old_iph = ip_hdr(skb); | 158 | struct iphdr *old_iph = ip_hdr(skb); |
320 | __be32 dst = tiph->daddr; | 159 | __be32 dst = tiph->daddr; |
321 | struct flowi4 fl4; | 160 | struct flowi4 fl4; |
161 | int err; | ||
322 | 162 | ||
323 | if (skb->protocol != htons(ETH_P_IP)) | 163 | if (skb->protocol != htons(ETH_P_IP)) |
324 | goto tx_error; | 164 | goto tx_error; |
@@ -367,8 +207,10 @@ static netdev_tx_t vti_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) | |||
367 | nf_reset(skb); | 207 | nf_reset(skb); |
368 | skb->dev = skb_dst(skb)->dev; | 208 | skb->dev = skb_dst(skb)->dev; |
369 | 209 | ||
370 | tstats = this_cpu_ptr(dev->tstats); | 210 | err = dst_output(skb); |
371 | VTI_XMIT(tstats, &dev->stats); | 211 | if (net_xmit_eval(err) == 0) |
212 | err = skb->len; | ||
213 | iptunnel_xmit_stats(err, &dev->stats, dev->tstats); | ||
372 | return NETDEV_TX_OK; | 214 | return NETDEV_TX_OK; |
373 | 215 | ||
374 | tx_error_icmp: | 216 | tx_error_icmp: |
@@ -379,198 +221,57 @@ tx_error: | |||
379 | return NETDEV_TX_OK; | 221 | return NETDEV_TX_OK; |
380 | } | 222 | } |
381 | 223 | ||
382 | static int vti_tunnel_bind_dev(struct net_device *dev) | ||
383 | { | ||
384 | struct net_device *tdev = NULL; | ||
385 | struct ip_tunnel *tunnel; | ||
386 | struct iphdr *iph; | ||
387 | |||
388 | tunnel = netdev_priv(dev); | ||
389 | iph = &tunnel->parms.iph; | ||
390 | |||
391 | if (iph->daddr) { | ||
392 | struct rtable *rt; | ||
393 | struct flowi4 fl4; | ||
394 | memset(&fl4, 0, sizeof(fl4)); | ||
395 | flowi4_init_output(&fl4, tunnel->parms.link, | ||
396 | be32_to_cpu(tunnel->parms.i_key), | ||
397 | RT_TOS(iph->tos), RT_SCOPE_UNIVERSE, | ||
398 | IPPROTO_IPIP, 0, | ||
399 | iph->daddr, iph->saddr, 0, 0); | ||
400 | rt = ip_route_output_key(dev_net(dev), &fl4); | ||
401 | if (!IS_ERR(rt)) { | ||
402 | tdev = rt->dst.dev; | ||
403 | ip_rt_put(rt); | ||
404 | } | ||
405 | dev->flags |= IFF_POINTOPOINT; | ||
406 | } | ||
407 | |||
408 | if (!tdev && tunnel->parms.link) | ||
409 | tdev = __dev_get_by_index(dev_net(dev), tunnel->parms.link); | ||
410 | |||
411 | if (tdev) { | ||
412 | dev->hard_header_len = tdev->hard_header_len + | ||
413 | sizeof(struct iphdr); | ||
414 | dev->mtu = tdev->mtu; | ||
415 | } | ||
416 | dev->iflink = tunnel->parms.link; | ||
417 | return dev->mtu; | ||
418 | } | ||
419 | |||
420 | static int | 224 | static int |
421 | vti_tunnel_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | 225 | vti_tunnel_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) |
422 | { | 226 | { |
423 | int err = 0; | 227 | int err = 0; |
424 | struct ip_tunnel_parm p; | 228 | struct ip_tunnel_parm p; |
425 | struct ip_tunnel *t; | ||
426 | struct net *net = dev_net(dev); | ||
427 | struct vti_net *ipn = net_generic(net, vti_net_id); | ||
428 | |||
429 | switch (cmd) { | ||
430 | case SIOCGETTUNNEL: | ||
431 | t = NULL; | ||
432 | if (dev == ipn->fb_tunnel_dev) { | ||
433 | if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, | ||
434 | sizeof(p))) { | ||
435 | err = -EFAULT; | ||
436 | break; | ||
437 | } | ||
438 | t = vti_tunnel_locate(net, &p, 0); | ||
439 | } | ||
440 | if (t == NULL) | ||
441 | t = netdev_priv(dev); | ||
442 | memcpy(&p, &t->parms, sizeof(p)); | ||
443 | p.i_flags |= GRE_KEY | VTI_ISVTI; | ||
444 | p.o_flags |= GRE_KEY; | ||
445 | if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p))) | ||
446 | err = -EFAULT; | ||
447 | break; | ||
448 | |||
449 | case SIOCADDTUNNEL: | ||
450 | case SIOCCHGTUNNEL: | ||
451 | err = -EPERM; | ||
452 | if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) | ||
453 | goto done; | ||
454 | 229 | ||
455 | err = -EFAULT; | 230 | if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) |
456 | if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) | 231 | return -EFAULT; |
457 | goto done; | ||
458 | 232 | ||
459 | err = -EINVAL; | 233 | if (cmd == SIOCADDTUNNEL || cmd == SIOCCHGTUNNEL) { |
460 | if (p.iph.version != 4 || p.iph.protocol != IPPROTO_IPIP || | 234 | if (p.iph.version != 4 || p.iph.protocol != IPPROTO_IPIP || |
461 | p.iph.ihl != 5) | 235 | p.iph.ihl != 5) |
462 | goto done; | 236 | return -EINVAL; |
463 | 237 | } | |
464 | t = vti_tunnel_locate(net, &p, cmd == SIOCADDTUNNEL); | ||
465 | |||
466 | if (dev != ipn->fb_tunnel_dev && cmd == SIOCCHGTUNNEL) { | ||
467 | if (t != NULL) { | ||
468 | if (t->dev != dev) { | ||
469 | err = -EEXIST; | ||
470 | break; | ||
471 | } | ||
472 | } else { | ||
473 | if (((dev->flags&IFF_POINTOPOINT) && | ||
474 | !p.iph.daddr) || | ||
475 | (!(dev->flags&IFF_POINTOPOINT) && | ||
476 | p.iph.daddr)) { | ||
477 | err = -EINVAL; | ||
478 | break; | ||
479 | } | ||
480 | t = netdev_priv(dev); | ||
481 | vti_tunnel_unlink(ipn, t); | ||
482 | synchronize_net(); | ||
483 | t->parms.iph.saddr = p.iph.saddr; | ||
484 | t->parms.iph.daddr = p.iph.daddr; | ||
485 | t->parms.i_key = p.i_key; | ||
486 | t->parms.o_key = p.o_key; | ||
487 | t->parms.iph.protocol = IPPROTO_IPIP; | ||
488 | memcpy(dev->dev_addr, &p.iph.saddr, 4); | ||
489 | memcpy(dev->broadcast, &p.iph.daddr, 4); | ||
490 | vti_tunnel_link(ipn, t); | ||
491 | netdev_state_change(dev); | ||
492 | } | ||
493 | } | ||
494 | |||
495 | if (t) { | ||
496 | err = 0; | ||
497 | if (cmd == SIOCCHGTUNNEL) { | ||
498 | t->parms.i_key = p.i_key; | ||
499 | t->parms.o_key = p.o_key; | ||
500 | if (t->parms.link != p.link) { | ||
501 | t->parms.link = p.link; | ||
502 | vti_tunnel_bind_dev(dev); | ||
503 | netdev_state_change(dev); | ||
504 | } | ||
505 | } | ||
506 | p.i_flags |= GRE_KEY | VTI_ISVTI; | ||
507 | p.o_flags |= GRE_KEY; | ||
508 | if (copy_to_user(ifr->ifr_ifru.ifru_data, &t->parms, | ||
509 | sizeof(p))) | ||
510 | err = -EFAULT; | ||
511 | } else | ||
512 | err = (cmd == SIOCADDTUNNEL ? -ENOBUFS : -ENOENT); | ||
513 | break; | ||
514 | 238 | ||
515 | case SIOCDELTUNNEL: | 239 | err = ip_tunnel_ioctl(dev, &p, cmd); |
516 | err = -EPERM; | 240 | if (err) |
517 | if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) | 241 | return err; |
518 | goto done; | ||
519 | |||
520 | if (dev == ipn->fb_tunnel_dev) { | ||
521 | err = -EFAULT; | ||
522 | if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, | ||
523 | sizeof(p))) | ||
524 | goto done; | ||
525 | err = -ENOENT; | ||
526 | |||
527 | t = vti_tunnel_locate(net, &p, 0); | ||
528 | if (t == NULL) | ||
529 | goto done; | ||
530 | err = -EPERM; | ||
531 | if (t->dev == ipn->fb_tunnel_dev) | ||
532 | goto done; | ||
533 | dev = t->dev; | ||
534 | } | ||
535 | unregister_netdevice(dev); | ||
536 | err = 0; | ||
537 | break; | ||
538 | 242 | ||
539 | default: | 243 | if (cmd != SIOCDELTUNNEL) { |
540 | err = -EINVAL; | 244 | p.i_flags |= GRE_KEY | VTI_ISVTI; |
245 | p.o_flags |= GRE_KEY; | ||
541 | } | 246 | } |
542 | 247 | ||
543 | done: | 248 | if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p))) |
544 | return err; | 249 | return -EFAULT; |
545 | } | ||
546 | |||
547 | static int vti_tunnel_change_mtu(struct net_device *dev, int new_mtu) | ||
548 | { | ||
549 | if (new_mtu < 68 || new_mtu > 0xFFF8) | ||
550 | return -EINVAL; | ||
551 | dev->mtu = new_mtu; | ||
552 | return 0; | 250 | return 0; |
553 | } | 251 | } |
554 | 252 | ||
555 | static const struct net_device_ops vti_netdev_ops = { | 253 | static const struct net_device_ops vti_netdev_ops = { |
556 | .ndo_init = vti_tunnel_init, | 254 | .ndo_init = vti_tunnel_init, |
557 | .ndo_uninit = vti_tunnel_uninit, | 255 | .ndo_uninit = ip_tunnel_uninit, |
558 | .ndo_start_xmit = vti_tunnel_xmit, | 256 | .ndo_start_xmit = vti_tunnel_xmit, |
559 | .ndo_do_ioctl = vti_tunnel_ioctl, | 257 | .ndo_do_ioctl = vti_tunnel_ioctl, |
560 | .ndo_change_mtu = vti_tunnel_change_mtu, | 258 | .ndo_change_mtu = ip_tunnel_change_mtu, |
561 | .ndo_get_stats64 = ip_tunnel_get_stats64, | 259 | .ndo_get_stats64 = ip_tunnel_get_stats64, |
562 | }; | 260 | }; |
563 | 261 | ||
564 | static void vti_dev_free(struct net_device *dev) | 262 | static void vti_tunnel_setup(struct net_device *dev) |
565 | { | 263 | { |
566 | free_percpu(dev->tstats); | 264 | dev->netdev_ops = &vti_netdev_ops; |
567 | free_netdev(dev); | 265 | ip_tunnel_setup(dev, vti_net_id); |
568 | } | 266 | } |
569 | 267 | ||
570 | static void vti_tunnel_setup(struct net_device *dev) | 268 | static int vti_tunnel_init(struct net_device *dev) |
571 | { | 269 | { |
572 | dev->netdev_ops = &vti_netdev_ops; | 270 | struct ip_tunnel *tunnel = netdev_priv(dev); |
573 | dev->destructor = vti_dev_free; | 271 | struct iphdr *iph = &tunnel->parms.iph; |
272 | |||
273 | memcpy(dev->dev_addr, &iph->saddr, 4); | ||
274 | memcpy(dev->broadcast, &iph->daddr, 4); | ||
574 | 275 | ||
575 | dev->type = ARPHRD_TUNNEL; | 276 | dev->type = ARPHRD_TUNNEL; |
576 | dev->hard_header_len = LL_MAX_HEADER + sizeof(struct iphdr); | 277 | dev->hard_header_len = LL_MAX_HEADER + sizeof(struct iphdr); |
@@ -581,38 +282,18 @@ static void vti_tunnel_setup(struct net_device *dev) | |||
581 | dev->features |= NETIF_F_NETNS_LOCAL; | 282 | dev->features |= NETIF_F_NETNS_LOCAL; |
582 | dev->features |= NETIF_F_LLTX; | 283 | dev->features |= NETIF_F_LLTX; |
583 | dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; | 284 | dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; |
584 | } | ||
585 | 285 | ||
586 | static int vti_tunnel_init(struct net_device *dev) | 286 | return ip_tunnel_init(dev); |
587 | { | ||
588 | struct ip_tunnel *tunnel = netdev_priv(dev); | ||
589 | |||
590 | tunnel->dev = dev; | ||
591 | strcpy(tunnel->parms.name, dev->name); | ||
592 | |||
593 | memcpy(dev->dev_addr, &tunnel->parms.iph.saddr, 4); | ||
594 | memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4); | ||
595 | |||
596 | dev->tstats = alloc_percpu(struct pcpu_tstats); | ||
597 | if (!dev->tstats) | ||
598 | return -ENOMEM; | ||
599 | |||
600 | return 0; | ||
601 | } | 287 | } |
602 | 288 | ||
603 | static int __net_init vti_fb_tunnel_init(struct net_device *dev) | 289 | static void __net_init vti_fb_tunnel_init(struct net_device *dev) |
604 | { | 290 | { |
605 | struct ip_tunnel *tunnel = netdev_priv(dev); | 291 | struct ip_tunnel *tunnel = netdev_priv(dev); |
606 | struct iphdr *iph = &tunnel->parms.iph; | 292 | struct iphdr *iph = &tunnel->parms.iph; |
607 | struct vti_net *ipn = net_generic(dev_net(dev), vti_net_id); | ||
608 | 293 | ||
609 | iph->version = 4; | 294 | iph->version = 4; |
610 | iph->protocol = IPPROTO_IPIP; | 295 | iph->protocol = IPPROTO_IPIP; |
611 | iph->ihl = 5; | 296 | iph->ihl = 5; |
612 | |||
613 | dev_hold(dev); | ||
614 | rcu_assign_pointer(ipn->tunnels_wc[0], tunnel); | ||
615 | return 0; | ||
616 | } | 297 | } |
617 | 298 | ||
618 | static struct xfrm_tunnel vti_handler __read_mostly = { | 299 | static struct xfrm_tunnel vti_handler __read_mostly = { |
@@ -621,76 +302,30 @@ static struct xfrm_tunnel vti_handler __read_mostly = { | |||
621 | .priority = 1, | 302 | .priority = 1, |
622 | }; | 303 | }; |
623 | 304 | ||
624 | static void vti_destroy_tunnels(struct vti_net *ipn, struct list_head *head) | ||
625 | { | ||
626 | int prio; | ||
627 | |||
628 | for (prio = 1; prio < 4; prio++) { | ||
629 | int h; | ||
630 | for (h = 0; h < HASH_SIZE; h++) { | ||
631 | struct ip_tunnel *t; | ||
632 | |||
633 | t = rtnl_dereference(ipn->tunnels[prio][h]); | ||
634 | while (t != NULL) { | ||
635 | unregister_netdevice_queue(t->dev, head); | ||
636 | t = rtnl_dereference(t->next); | ||
637 | } | ||
638 | } | ||
639 | } | ||
640 | } | ||
641 | |||
642 | static int __net_init vti_init_net(struct net *net) | 305 | static int __net_init vti_init_net(struct net *net) |
643 | { | 306 | { |
644 | int err; | 307 | int err; |
645 | struct vti_net *ipn = net_generic(net, vti_net_id); | 308 | struct ip_tunnel_net *itn; |
646 | |||
647 | ipn->tunnels[0] = ipn->tunnels_wc; | ||
648 | ipn->tunnels[1] = ipn->tunnels_l; | ||
649 | ipn->tunnels[2] = ipn->tunnels_r; | ||
650 | ipn->tunnels[3] = ipn->tunnels_r_l; | ||
651 | |||
652 | ipn->fb_tunnel_dev = alloc_netdev(sizeof(struct ip_tunnel), | ||
653 | "ip_vti0", | ||
654 | vti_tunnel_setup); | ||
655 | if (!ipn->fb_tunnel_dev) { | ||
656 | err = -ENOMEM; | ||
657 | goto err_alloc_dev; | ||
658 | } | ||
659 | dev_net_set(ipn->fb_tunnel_dev, net); | ||
660 | |||
661 | err = vti_fb_tunnel_init(ipn->fb_tunnel_dev); | ||
662 | if (err) | ||
663 | goto err_reg_dev; | ||
664 | ipn->fb_tunnel_dev->rtnl_link_ops = &vti_link_ops; | ||
665 | 309 | ||
666 | err = register_netdev(ipn->fb_tunnel_dev); | 310 | err = ip_tunnel_init_net(net, vti_net_id, &vti_link_ops, "ip_vti0"); |
667 | if (err) | 311 | if (err) |
668 | goto err_reg_dev; | 312 | return err; |
313 | itn = net_generic(net, vti_net_id); | ||
314 | vti_fb_tunnel_init(itn->fb_tunnel_dev); | ||
669 | return 0; | 315 | return 0; |
670 | |||
671 | err_reg_dev: | ||
672 | vti_dev_free(ipn->fb_tunnel_dev); | ||
673 | err_alloc_dev: | ||
674 | /* nothing */ | ||
675 | return err; | ||
676 | } | 316 | } |
677 | 317 | ||
678 | static void __net_exit vti_exit_net(struct net *net) | 318 | static void __net_exit vti_exit_net(struct net *net) |
679 | { | 319 | { |
680 | struct vti_net *ipn = net_generic(net, vti_net_id); | 320 | struct ip_tunnel_net *itn = net_generic(net, vti_net_id); |
681 | LIST_HEAD(list); | 321 | ip_tunnel_delete_net(itn); |
682 | |||
683 | rtnl_lock(); | ||
684 | vti_destroy_tunnels(ipn, &list); | ||
685 | unregister_netdevice_many(&list); | ||
686 | rtnl_unlock(); | ||
687 | } | 322 | } |
688 | 323 | ||
689 | static struct pernet_operations vti_net_ops = { | 324 | static struct pernet_operations vti_net_ops = { |
690 | .init = vti_init_net, | 325 | .init = vti_init_net, |
691 | .exit = vti_exit_net, | 326 | .exit = vti_exit_net, |
692 | .id = &vti_net_id, | 327 | .id = &vti_net_id, |
693 | .size = sizeof(struct vti_net), | 328 | .size = sizeof(struct ip_tunnel_net), |
694 | }; | 329 | }; |
695 | 330 | ||
696 | static int vti_tunnel_validate(struct nlattr *tb[], struct nlattr *data[]) | 331 | static int vti_tunnel_validate(struct nlattr *tb[], struct nlattr *data[]) |
@@ -728,78 +363,19 @@ static void vti_netlink_parms(struct nlattr *data[], | |||
728 | static int vti_newlink(struct net *src_net, struct net_device *dev, | 363 | static int vti_newlink(struct net *src_net, struct net_device *dev, |
729 | struct nlattr *tb[], struct nlattr *data[]) | 364 | struct nlattr *tb[], struct nlattr *data[]) |
730 | { | 365 | { |
731 | struct ip_tunnel *nt; | 366 | struct ip_tunnel_parm parms; |
732 | struct net *net = dev_net(dev); | ||
733 | struct vti_net *ipn = net_generic(net, vti_net_id); | ||
734 | int mtu; | ||
735 | int err; | ||
736 | |||
737 | nt = netdev_priv(dev); | ||
738 | vti_netlink_parms(data, &nt->parms); | ||
739 | |||
740 | if (vti_tunnel_locate(net, &nt->parms, 0)) | ||
741 | return -EEXIST; | ||
742 | 367 | ||
743 | mtu = vti_tunnel_bind_dev(dev); | 368 | vti_netlink_parms(data, &parms); |
744 | if (!tb[IFLA_MTU]) | 369 | return ip_tunnel_newlink(dev, tb, &parms); |
745 | dev->mtu = mtu; | ||
746 | |||
747 | err = register_netdevice(dev); | ||
748 | if (err) | ||
749 | goto out; | ||
750 | |||
751 | dev_hold(dev); | ||
752 | vti_tunnel_link(ipn, nt); | ||
753 | |||
754 | out: | ||
755 | return err; | ||
756 | } | 370 | } |
757 | 371 | ||
758 | static int vti_changelink(struct net_device *dev, struct nlattr *tb[], | 372 | static int vti_changelink(struct net_device *dev, struct nlattr *tb[], |
759 | struct nlattr *data[]) | 373 | struct nlattr *data[]) |
760 | { | 374 | { |
761 | struct ip_tunnel *t, *nt; | ||
762 | struct net *net = dev_net(dev); | ||
763 | struct vti_net *ipn = net_generic(net, vti_net_id); | ||
764 | struct ip_tunnel_parm p; | 375 | struct ip_tunnel_parm p; |
765 | int mtu; | ||
766 | |||
767 | if (dev == ipn->fb_tunnel_dev) | ||
768 | return -EINVAL; | ||
769 | 376 | ||
770 | nt = netdev_priv(dev); | ||
771 | vti_netlink_parms(data, &p); | 377 | vti_netlink_parms(data, &p); |
772 | 378 | return ip_tunnel_changelink(dev, tb, &p); | |
773 | t = vti_tunnel_locate(net, &p, 0); | ||
774 | |||
775 | if (t) { | ||
776 | if (t->dev != dev) | ||
777 | return -EEXIST; | ||
778 | } else { | ||
779 | t = nt; | ||
780 | |||
781 | vti_tunnel_unlink(ipn, t); | ||
782 | t->parms.iph.saddr = p.iph.saddr; | ||
783 | t->parms.iph.daddr = p.iph.daddr; | ||
784 | t->parms.i_key = p.i_key; | ||
785 | t->parms.o_key = p.o_key; | ||
786 | if (dev->type != ARPHRD_ETHER) { | ||
787 | memcpy(dev->dev_addr, &p.iph.saddr, 4); | ||
788 | memcpy(dev->broadcast, &p.iph.daddr, 4); | ||
789 | } | ||
790 | vti_tunnel_link(ipn, t); | ||
791 | netdev_state_change(dev); | ||
792 | } | ||
793 | |||
794 | if (t->parms.link != p.link) { | ||
795 | t->parms.link = p.link; | ||
796 | mtu = vti_tunnel_bind_dev(dev); | ||
797 | if (!tb[IFLA_MTU]) | ||
798 | dev->mtu = mtu; | ||
799 | netdev_state_change(dev); | ||
800 | } | ||
801 | |||
802 | return 0; | ||
803 | } | 379 | } |
804 | 380 | ||
805 | static size_t vti_get_size(const struct net_device *dev) | 381 | static size_t vti_get_size(const struct net_device *dev) |
@@ -865,7 +441,7 @@ static int __init vti_init(void) | |||
865 | err = xfrm4_mode_tunnel_input_register(&vti_handler); | 441 | err = xfrm4_mode_tunnel_input_register(&vti_handler); |
866 | if (err < 0) { | 442 | if (err < 0) { |
867 | unregister_pernet_device(&vti_net_ops); | 443 | unregister_pernet_device(&vti_net_ops); |
868 | pr_info(KERN_INFO "vti init: can't register tunnel\n"); | 444 | pr_info("vti init: can't register tunnel\n"); |
869 | } | 445 | } |
870 | 446 | ||
871 | err = rtnl_link_register(&vti_link_ops); | 447 | err = rtnl_link_register(&vti_link_ops); |