diff options
Diffstat (limited to 'net/ipv4/ipip.c')
-rw-r--r-- | net/ipv4/ipip.c | 97 |
1 files changed, 49 insertions, 48 deletions
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index ae40ed1ba560..eda04fed3379 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c | |||
@@ -119,7 +119,7 @@ | |||
119 | #define HASH_SIZE 16 | 119 | #define HASH_SIZE 16 |
120 | #define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF) | 120 | #define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF) |
121 | 121 | ||
122 | static int ipip_net_id; | 122 | static int ipip_net_id __read_mostly; |
123 | struct ipip_net { | 123 | struct ipip_net { |
124 | struct ip_tunnel *tunnels_r_l[HASH_SIZE]; | 124 | struct ip_tunnel *tunnels_r_l[HASH_SIZE]; |
125 | struct ip_tunnel *tunnels_r[HASH_SIZE]; | 125 | struct ip_tunnel *tunnels_r[HASH_SIZE]; |
@@ -134,7 +134,13 @@ static void ipip_fb_tunnel_init(struct net_device *dev); | |||
134 | static void ipip_tunnel_init(struct net_device *dev); | 134 | static void ipip_tunnel_init(struct net_device *dev); |
135 | static void ipip_tunnel_setup(struct net_device *dev); | 135 | static void ipip_tunnel_setup(struct net_device *dev); |
136 | 136 | ||
137 | static DEFINE_RWLOCK(ipip_lock); | 137 | /* |
138 | * Locking : hash tables are protected by RCU and a spinlock | ||
139 | */ | ||
140 | static DEFINE_SPINLOCK(ipip_lock); | ||
141 | |||
142 | #define for_each_ip_tunnel_rcu(start) \ | ||
143 | for (t = rcu_dereference(start); t; t = rcu_dereference(t->next)) | ||
138 | 144 | ||
139 | static struct ip_tunnel * ipip_tunnel_lookup(struct net *net, | 145 | static struct ip_tunnel * ipip_tunnel_lookup(struct net *net, |
140 | __be32 remote, __be32 local) | 146 | __be32 remote, __be32 local) |
@@ -144,20 +150,21 @@ static struct ip_tunnel * ipip_tunnel_lookup(struct net *net, | |||
144 | struct ip_tunnel *t; | 150 | struct ip_tunnel *t; |
145 | struct ipip_net *ipn = net_generic(net, ipip_net_id); | 151 | struct ipip_net *ipn = net_generic(net, ipip_net_id); |
146 | 152 | ||
147 | for (t = ipn->tunnels_r_l[h0^h1]; t; t = t->next) { | 153 | for_each_ip_tunnel_rcu(ipn->tunnels_r_l[h0 ^ h1]) |
148 | if (local == t->parms.iph.saddr && | 154 | if (local == t->parms.iph.saddr && |
149 | remote == t->parms.iph.daddr && (t->dev->flags&IFF_UP)) | 155 | remote == t->parms.iph.daddr && (t->dev->flags&IFF_UP)) |
150 | return t; | 156 | return t; |
151 | } | 157 | |
152 | for (t = ipn->tunnels_r[h0]; t; t = t->next) { | 158 | for_each_ip_tunnel_rcu(ipn->tunnels_r[h0]) |
153 | if (remote == t->parms.iph.daddr && (t->dev->flags&IFF_UP)) | 159 | if (remote == t->parms.iph.daddr && (t->dev->flags&IFF_UP)) |
154 | return t; | 160 | return t; |
155 | } | 161 | |
156 | for (t = ipn->tunnels_l[h1]; t; t = t->next) { | 162 | for_each_ip_tunnel_rcu(ipn->tunnels_l[h1]) |
157 | if (local == t->parms.iph.saddr && (t->dev->flags&IFF_UP)) | 163 | if (local == t->parms.iph.saddr && (t->dev->flags&IFF_UP)) |
158 | return t; | 164 | return t; |
159 | } | 165 | |
160 | if ((t = ipn->tunnels_wc[0]) != NULL && (t->dev->flags&IFF_UP)) | 166 | t = rcu_dereference(ipn->tunnels_wc[0]); |
167 | if (t && (t->dev->flags&IFF_UP)) | ||
161 | return t; | 168 | return t; |
162 | return NULL; | 169 | return NULL; |
163 | } | 170 | } |
@@ -193,9 +200,9 @@ static void ipip_tunnel_unlink(struct ipip_net *ipn, struct ip_tunnel *t) | |||
193 | 200 | ||
194 | for (tp = ipip_bucket(ipn, t); *tp; tp = &(*tp)->next) { | 201 | for (tp = ipip_bucket(ipn, t); *tp; tp = &(*tp)->next) { |
195 | if (t == *tp) { | 202 | if (t == *tp) { |
196 | write_lock_bh(&ipip_lock); | 203 | spin_lock_bh(&ipip_lock); |
197 | *tp = t->next; | 204 | *tp = t->next; |
198 | write_unlock_bh(&ipip_lock); | 205 | spin_unlock_bh(&ipip_lock); |
199 | break; | 206 | break; |
200 | } | 207 | } |
201 | } | 208 | } |
@@ -205,10 +212,10 @@ static void ipip_tunnel_link(struct ipip_net *ipn, struct ip_tunnel *t) | |||
205 | { | 212 | { |
206 | struct ip_tunnel **tp = ipip_bucket(ipn, t); | 213 | struct ip_tunnel **tp = ipip_bucket(ipn, t); |
207 | 214 | ||
215 | spin_lock_bh(&ipip_lock); | ||
208 | t->next = *tp; | 216 | t->next = *tp; |
209 | write_lock_bh(&ipip_lock); | 217 | rcu_assign_pointer(*tp, t); |
210 | *tp = t; | 218 | spin_unlock_bh(&ipip_lock); |
211 | write_unlock_bh(&ipip_lock); | ||
212 | } | 219 | } |
213 | 220 | ||
214 | static struct ip_tunnel * ipip_tunnel_locate(struct net *net, | 221 | static struct ip_tunnel * ipip_tunnel_locate(struct net *net, |
@@ -267,9 +274,9 @@ static void ipip_tunnel_uninit(struct net_device *dev) | |||
267 | struct ipip_net *ipn = net_generic(net, ipip_net_id); | 274 | struct ipip_net *ipn = net_generic(net, ipip_net_id); |
268 | 275 | ||
269 | if (dev == ipn->fb_tunnel_dev) { | 276 | if (dev == ipn->fb_tunnel_dev) { |
270 | write_lock_bh(&ipip_lock); | 277 | spin_lock_bh(&ipip_lock); |
271 | ipn->tunnels_wc[0] = NULL; | 278 | ipn->tunnels_wc[0] = NULL; |
272 | write_unlock_bh(&ipip_lock); | 279 | spin_unlock_bh(&ipip_lock); |
273 | } else | 280 | } else |
274 | ipip_tunnel_unlink(ipn, netdev_priv(dev)); | 281 | ipip_tunnel_unlink(ipn, netdev_priv(dev)); |
275 | dev_put(dev); | 282 | dev_put(dev); |
@@ -318,7 +325,7 @@ static int ipip_err(struct sk_buff *skb, u32 info) | |||
318 | 325 | ||
319 | err = -ENOENT; | 326 | err = -ENOENT; |
320 | 327 | ||
321 | read_lock(&ipip_lock); | 328 | rcu_read_lock(); |
322 | t = ipip_tunnel_lookup(dev_net(skb->dev), iph->daddr, iph->saddr); | 329 | t = ipip_tunnel_lookup(dev_net(skb->dev), iph->daddr, iph->saddr); |
323 | if (t == NULL || t->parms.iph.daddr == 0) | 330 | if (t == NULL || t->parms.iph.daddr == 0) |
324 | goto out; | 331 | goto out; |
@@ -333,7 +340,7 @@ static int ipip_err(struct sk_buff *skb, u32 info) | |||
333 | t->err_count = 1; | 340 | t->err_count = 1; |
334 | t->err_time = jiffies; | 341 | t->err_time = jiffies; |
335 | out: | 342 | out: |
336 | read_unlock(&ipip_lock); | 343 | rcu_read_unlock(); |
337 | return err; | 344 | return err; |
338 | } | 345 | } |
339 | 346 | ||
@@ -351,11 +358,11 @@ static int ipip_rcv(struct sk_buff *skb) | |||
351 | struct ip_tunnel *tunnel; | 358 | struct ip_tunnel *tunnel; |
352 | const struct iphdr *iph = ip_hdr(skb); | 359 | const struct iphdr *iph = ip_hdr(skb); |
353 | 360 | ||
354 | read_lock(&ipip_lock); | 361 | rcu_read_lock(); |
355 | if ((tunnel = ipip_tunnel_lookup(dev_net(skb->dev), | 362 | if ((tunnel = ipip_tunnel_lookup(dev_net(skb->dev), |
356 | iph->saddr, iph->daddr)) != NULL) { | 363 | iph->saddr, iph->daddr)) != NULL) { |
357 | if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) { | 364 | if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) { |
358 | read_unlock(&ipip_lock); | 365 | rcu_read_unlock(); |
359 | kfree_skb(skb); | 366 | kfree_skb(skb); |
360 | return 0; | 367 | return 0; |
361 | } | 368 | } |
@@ -374,10 +381,10 @@ static int ipip_rcv(struct sk_buff *skb) | |||
374 | nf_reset(skb); | 381 | nf_reset(skb); |
375 | ipip_ecn_decapsulate(iph, skb); | 382 | ipip_ecn_decapsulate(iph, skb); |
376 | netif_rx(skb); | 383 | netif_rx(skb); |
377 | read_unlock(&ipip_lock); | 384 | rcu_read_unlock(); |
378 | return 0; | 385 | return 0; |
379 | } | 386 | } |
380 | read_unlock(&ipip_lock); | 387 | rcu_read_unlock(); |
381 | 388 | ||
382 | return -1; | 389 | return -1; |
383 | } | 390 | } |
@@ -390,7 +397,8 @@ static int ipip_rcv(struct sk_buff *skb) | |||
390 | static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) | 397 | static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) |
391 | { | 398 | { |
392 | struct ip_tunnel *tunnel = netdev_priv(dev); | 399 | struct ip_tunnel *tunnel = netdev_priv(dev); |
393 | struct net_device_stats *stats = &tunnel->dev->stats; | 400 | struct net_device_stats *stats = &dev->stats; |
401 | struct netdev_queue *txq = netdev_get_tx_queue(dev, 0); | ||
394 | struct iphdr *tiph = &tunnel->parms.iph; | 402 | struct iphdr *tiph = &tunnel->parms.iph; |
395 | u8 tos = tunnel->parms.iph.tos; | 403 | u8 tos = tunnel->parms.iph.tos; |
396 | __be16 df = tiph->frag_off; | 404 | __be16 df = tiph->frag_off; |
@@ -480,7 +488,7 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) | |||
480 | struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom); | 488 | struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom); |
481 | if (!new_skb) { | 489 | if (!new_skb) { |
482 | ip_rt_put(rt); | 490 | ip_rt_put(rt); |
483 | stats->tx_dropped++; | 491 | txq->tx_dropped++; |
484 | dev_kfree_skb(skb); | 492 | dev_kfree_skb(skb); |
485 | return NETDEV_TX_OK; | 493 | return NETDEV_TX_OK; |
486 | } | 494 | } |
@@ -748,33 +756,27 @@ static struct xfrm_tunnel ipip_handler = { | |||
748 | static const char banner[] __initconst = | 756 | static const char banner[] __initconst = |
749 | KERN_INFO "IPv4 over IPv4 tunneling driver\n"; | 757 | KERN_INFO "IPv4 over IPv4 tunneling driver\n"; |
750 | 758 | ||
751 | static void ipip_destroy_tunnels(struct ipip_net *ipn) | 759 | static void ipip_destroy_tunnels(struct ipip_net *ipn, struct list_head *head) |
752 | { | 760 | { |
753 | int prio; | 761 | int prio; |
754 | 762 | ||
755 | for (prio = 1; prio < 4; prio++) { | 763 | for (prio = 1; prio < 4; prio++) { |
756 | int h; | 764 | int h; |
757 | for (h = 0; h < HASH_SIZE; h++) { | 765 | for (h = 0; h < HASH_SIZE; h++) { |
758 | struct ip_tunnel *t; | 766 | struct ip_tunnel *t = ipn->tunnels[prio][h]; |
759 | while ((t = ipn->tunnels[prio][h]) != NULL) | 767 | |
760 | unregister_netdevice(t->dev); | 768 | while (t != NULL) { |
769 | unregister_netdevice_queue(t->dev, head); | ||
770 | t = t->next; | ||
771 | } | ||
761 | } | 772 | } |
762 | } | 773 | } |
763 | } | 774 | } |
764 | 775 | ||
765 | static int ipip_init_net(struct net *net) | 776 | static int ipip_init_net(struct net *net) |
766 | { | 777 | { |
778 | struct ipip_net *ipn = net_generic(net, ipip_net_id); | ||
767 | int err; | 779 | int err; |
768 | struct ipip_net *ipn; | ||
769 | |||
770 | err = -ENOMEM; | ||
771 | ipn = kzalloc(sizeof(struct ipip_net), GFP_KERNEL); | ||
772 | if (ipn == NULL) | ||
773 | goto err_alloc; | ||
774 | |||
775 | err = net_assign_generic(net, ipip_net_id, ipn); | ||
776 | if (err < 0) | ||
777 | goto err_assign; | ||
778 | 780 | ||
779 | ipn->tunnels[0] = ipn->tunnels_wc; | 781 | ipn->tunnels[0] = ipn->tunnels_wc; |
780 | ipn->tunnels[1] = ipn->tunnels_l; | 782 | ipn->tunnels[1] = ipn->tunnels_l; |
@@ -801,27 +803,26 @@ err_reg_dev: | |||
801 | free_netdev(ipn->fb_tunnel_dev); | 803 | free_netdev(ipn->fb_tunnel_dev); |
802 | err_alloc_dev: | 804 | err_alloc_dev: |
803 | /* nothing */ | 805 | /* nothing */ |
804 | err_assign: | ||
805 | kfree(ipn); | ||
806 | err_alloc: | ||
807 | return err; | 806 | return err; |
808 | } | 807 | } |
809 | 808 | ||
810 | static void ipip_exit_net(struct net *net) | 809 | static void ipip_exit_net(struct net *net) |
811 | { | 810 | { |
812 | struct ipip_net *ipn; | 811 | struct ipip_net *ipn = net_generic(net, ipip_net_id); |
812 | LIST_HEAD(list); | ||
813 | 813 | ||
814 | ipn = net_generic(net, ipip_net_id); | ||
815 | rtnl_lock(); | 814 | rtnl_lock(); |
816 | ipip_destroy_tunnels(ipn); | 815 | ipip_destroy_tunnels(ipn, &list); |
817 | unregister_netdevice(ipn->fb_tunnel_dev); | 816 | unregister_netdevice_queue(ipn->fb_tunnel_dev, &list); |
817 | unregister_netdevice_many(&list); | ||
818 | rtnl_unlock(); | 818 | rtnl_unlock(); |
819 | kfree(ipn); | ||
820 | } | 819 | } |
821 | 820 | ||
822 | static struct pernet_operations ipip_net_ops = { | 821 | static struct pernet_operations ipip_net_ops = { |
823 | .init = ipip_init_net, | 822 | .init = ipip_init_net, |
824 | .exit = ipip_exit_net, | 823 | .exit = ipip_exit_net, |
824 | .id = &ipip_net_id, | ||
825 | .size = sizeof(struct ipip_net), | ||
825 | }; | 826 | }; |
826 | 827 | ||
827 | static int __init ipip_init(void) | 828 | static int __init ipip_init(void) |
@@ -835,7 +836,7 @@ static int __init ipip_init(void) | |||
835 | return -EAGAIN; | 836 | return -EAGAIN; |
836 | } | 837 | } |
837 | 838 | ||
838 | err = register_pernet_gen_device(&ipip_net_id, &ipip_net_ops); | 839 | err = register_pernet_device(&ipip_net_ops); |
839 | if (err) | 840 | if (err) |
840 | xfrm4_tunnel_deregister(&ipip_handler, AF_INET); | 841 | xfrm4_tunnel_deregister(&ipip_handler, AF_INET); |
841 | 842 | ||
@@ -847,7 +848,7 @@ static void __exit ipip_fini(void) | |||
847 | if (xfrm4_tunnel_deregister(&ipip_handler, AF_INET)) | 848 | if (xfrm4_tunnel_deregister(&ipip_handler, AF_INET)) |
848 | printk(KERN_INFO "ipip close: can't deregister tunnel\n"); | 849 | printk(KERN_INFO "ipip close: can't deregister tunnel\n"); |
849 | 850 | ||
850 | unregister_pernet_gen_device(ipip_net_id, &ipip_net_ops); | 851 | unregister_pernet_device(&ipip_net_ops); |
851 | } | 852 | } |
852 | 853 | ||
853 | module_init(ipip_init); | 854 | module_init(ipip_init); |