diff options
author | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
---|---|---|
committer | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
commit | ada47b5fe13d89735805b566185f4885f5a3f750 (patch) | |
tree | 644b88f8a71896307d71438e9b3af49126ffb22b /net/ipv6/ip6_tunnel.c | |
parent | 43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff) | |
parent | 3280f21d43ee541f97f8cda5792150d2dbec20d5 (diff) |
Merge branch 'wip-2.6.34' into old-private-masterarchived-private-master
Diffstat (limited to 'net/ipv6/ip6_tunnel.c')
-rw-r--r-- | net/ipv6/ip6_tunnel.c | 135 |
1 files changed, 67 insertions, 68 deletions
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index c595bbe1ed99..2599870747ec 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c | |||
@@ -37,6 +37,7 @@ | |||
37 | #include <linux/route.h> | 37 | #include <linux/route.h> |
38 | #include <linux/rtnetlink.h> | 38 | #include <linux/rtnetlink.h> |
39 | #include <linux/netfilter_ipv6.h> | 39 | #include <linux/netfilter_ipv6.h> |
40 | #include <linux/slab.h> | ||
40 | 41 | ||
41 | #include <asm/uaccess.h> | 42 | #include <asm/uaccess.h> |
42 | #include <asm/atomic.h> | 43 | #include <asm/atomic.h> |
@@ -74,11 +75,10 @@ MODULE_LICENSE("GPL"); | |||
74 | (addr)->s6_addr32[2] ^ (addr)->s6_addr32[3]) & \ | 75 | (addr)->s6_addr32[2] ^ (addr)->s6_addr32[3]) & \ |
75 | (HASH_SIZE - 1)) | 76 | (HASH_SIZE - 1)) |
76 | 77 | ||
77 | static void ip6_fb_tnl_dev_init(struct net_device *dev); | ||
78 | static void ip6_tnl_dev_init(struct net_device *dev); | 78 | static void ip6_tnl_dev_init(struct net_device *dev); |
79 | static void ip6_tnl_dev_setup(struct net_device *dev); | 79 | static void ip6_tnl_dev_setup(struct net_device *dev); |
80 | 80 | ||
81 | static int ip6_tnl_net_id; | 81 | static int ip6_tnl_net_id __read_mostly; |
82 | struct ip6_tnl_net { | 82 | struct ip6_tnl_net { |
83 | /* the IPv6 tunnel fallback device */ | 83 | /* the IPv6 tunnel fallback device */ |
84 | struct net_device *fb_tnl_dev; | 84 | struct net_device *fb_tnl_dev; |
@@ -88,8 +88,10 @@ struct ip6_tnl_net { | |||
88 | struct ip6_tnl **tnls[2]; | 88 | struct ip6_tnl **tnls[2]; |
89 | }; | 89 | }; |
90 | 90 | ||
91 | /* lock for the tunnel lists */ | 91 | /* |
92 | static DEFINE_RWLOCK(ip6_tnl_lock); | 92 | * Locking : hash tables are protected by RCU and a spinlock |
93 | */ | ||
94 | static DEFINE_SPINLOCK(ip6_tnl_lock); | ||
93 | 95 | ||
94 | static inline struct dst_entry *ip6_tnl_dst_check(struct ip6_tnl *t) | 96 | static inline struct dst_entry *ip6_tnl_dst_check(struct ip6_tnl *t) |
95 | { | 97 | { |
@@ -130,6 +132,9 @@ static inline void ip6_tnl_dst_store(struct ip6_tnl *t, struct dst_entry *dst) | |||
130 | * else %NULL | 132 | * else %NULL |
131 | **/ | 133 | **/ |
132 | 134 | ||
135 | #define for_each_ip6_tunnel_rcu(start) \ | ||
136 | for (t = rcu_dereference(start); t; t = rcu_dereference(t->next)) | ||
137 | |||
133 | static struct ip6_tnl * | 138 | static struct ip6_tnl * |
134 | ip6_tnl_lookup(struct net *net, struct in6_addr *remote, struct in6_addr *local) | 139 | ip6_tnl_lookup(struct net *net, struct in6_addr *remote, struct in6_addr *local) |
135 | { | 140 | { |
@@ -138,13 +143,14 @@ ip6_tnl_lookup(struct net *net, struct in6_addr *remote, struct in6_addr *local) | |||
138 | struct ip6_tnl *t; | 143 | struct ip6_tnl *t; |
139 | struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); | 144 | struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); |
140 | 145 | ||
141 | for (t = ip6n->tnls_r_l[h0 ^ h1]; t; t = t->next) { | 146 | for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[h0 ^ h1]) { |
142 | if (ipv6_addr_equal(local, &t->parms.laddr) && | 147 | if (ipv6_addr_equal(local, &t->parms.laddr) && |
143 | ipv6_addr_equal(remote, &t->parms.raddr) && | 148 | ipv6_addr_equal(remote, &t->parms.raddr) && |
144 | (t->dev->flags & IFF_UP)) | 149 | (t->dev->flags & IFF_UP)) |
145 | return t; | 150 | return t; |
146 | } | 151 | } |
147 | if ((t = ip6n->tnls_wc[0]) != NULL && (t->dev->flags & IFF_UP)) | 152 | t = rcu_dereference(ip6n->tnls_wc[0]); |
153 | if (t && (t->dev->flags & IFF_UP)) | ||
148 | return t; | 154 | return t; |
149 | 155 | ||
150 | return NULL; | 156 | return NULL; |
@@ -186,10 +192,10 @@ ip6_tnl_link(struct ip6_tnl_net *ip6n, struct ip6_tnl *t) | |||
186 | { | 192 | { |
187 | struct ip6_tnl **tp = ip6_tnl_bucket(ip6n, &t->parms); | 193 | struct ip6_tnl **tp = ip6_tnl_bucket(ip6n, &t->parms); |
188 | 194 | ||
195 | spin_lock_bh(&ip6_tnl_lock); | ||
189 | t->next = *tp; | 196 | t->next = *tp; |
190 | write_lock_bh(&ip6_tnl_lock); | 197 | rcu_assign_pointer(*tp, t); |
191 | *tp = t; | 198 | spin_unlock_bh(&ip6_tnl_lock); |
192 | write_unlock_bh(&ip6_tnl_lock); | ||
193 | } | 199 | } |
194 | 200 | ||
195 | /** | 201 | /** |
@@ -204,9 +210,9 @@ ip6_tnl_unlink(struct ip6_tnl_net *ip6n, struct ip6_tnl *t) | |||
204 | 210 | ||
205 | for (tp = ip6_tnl_bucket(ip6n, &t->parms); *tp; tp = &(*tp)->next) { | 211 | for (tp = ip6_tnl_bucket(ip6n, &t->parms); *tp; tp = &(*tp)->next) { |
206 | if (t == *tp) { | 212 | if (t == *tp) { |
207 | write_lock_bh(&ip6_tnl_lock); | 213 | spin_lock_bh(&ip6_tnl_lock); |
208 | *tp = t->next; | 214 | *tp = t->next; |
209 | write_unlock_bh(&ip6_tnl_lock); | 215 | spin_unlock_bh(&ip6_tnl_lock); |
210 | break; | 216 | break; |
211 | } | 217 | } |
212 | } | 218 | } |
@@ -313,9 +319,9 @@ ip6_tnl_dev_uninit(struct net_device *dev) | |||
313 | struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); | 319 | struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); |
314 | 320 | ||
315 | if (dev == ip6n->fb_tnl_dev) { | 321 | if (dev == ip6n->fb_tnl_dev) { |
316 | write_lock_bh(&ip6_tnl_lock); | 322 | spin_lock_bh(&ip6_tnl_lock); |
317 | ip6n->tnls_wc[0] = NULL; | 323 | ip6n->tnls_wc[0] = NULL; |
318 | write_unlock_bh(&ip6_tnl_lock); | 324 | spin_unlock_bh(&ip6_tnl_lock); |
319 | } else { | 325 | } else { |
320 | ip6_tnl_unlink(ip6n, t); | 326 | ip6_tnl_unlink(ip6n, t); |
321 | } | 327 | } |
@@ -409,7 +415,7 @@ ip6_tnl_err(struct sk_buff *skb, __u8 ipproto, struct inet6_skb_parm *opt, | |||
409 | in trouble since we might need the source address for further | 415 | in trouble since we might need the source address for further |
410 | processing of the error. */ | 416 | processing of the error. */ |
411 | 417 | ||
412 | read_lock(&ip6_tnl_lock); | 418 | rcu_read_lock(); |
413 | if ((t = ip6_tnl_lookup(dev_net(skb->dev), &ipv6h->daddr, | 419 | if ((t = ip6_tnl_lookup(dev_net(skb->dev), &ipv6h->daddr, |
414 | &ipv6h->saddr)) == NULL) | 420 | &ipv6h->saddr)) == NULL) |
415 | goto out; | 421 | goto out; |
@@ -482,7 +488,7 @@ ip6_tnl_err(struct sk_buff *skb, __u8 ipproto, struct inet6_skb_parm *opt, | |||
482 | *msg = rel_msg; | 488 | *msg = rel_msg; |
483 | 489 | ||
484 | out: | 490 | out: |
485 | read_unlock(&ip6_tnl_lock); | 491 | rcu_read_unlock(); |
486 | return err; | 492 | return err; |
487 | } | 493 | } |
488 | 494 | ||
@@ -617,7 +623,7 @@ ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
617 | if (rt && rt->rt6i_dev) | 623 | if (rt && rt->rt6i_dev) |
618 | skb2->dev = rt->rt6i_dev; | 624 | skb2->dev = rt->rt6i_dev; |
619 | 625 | ||
620 | icmpv6_send(skb2, rel_type, rel_code, rel_info, skb2->dev); | 626 | icmpv6_send(skb2, rel_type, rel_code, rel_info); |
621 | 627 | ||
622 | if (rt) | 628 | if (rt) |
623 | dst_release(&rt->u.dst); | 629 | dst_release(&rt->u.dst); |
@@ -652,6 +658,7 @@ static void ip6ip6_dscp_ecn_decapsulate(struct ip6_tnl *t, | |||
652 | IP6_ECN_set_ce(ipv6_hdr(skb)); | 658 | IP6_ECN_set_ce(ipv6_hdr(skb)); |
653 | } | 659 | } |
654 | 660 | ||
661 | /* called with rcu_read_lock() */ | ||
655 | static inline int ip6_tnl_rcv_ctl(struct ip6_tnl *t) | 662 | static inline int ip6_tnl_rcv_ctl(struct ip6_tnl *t) |
656 | { | 663 | { |
657 | struct ip6_tnl_parm *p = &t->parms; | 664 | struct ip6_tnl_parm *p = &t->parms; |
@@ -662,15 +669,13 @@ static inline int ip6_tnl_rcv_ctl(struct ip6_tnl *t) | |||
662 | struct net_device *ldev = NULL; | 669 | struct net_device *ldev = NULL; |
663 | 670 | ||
664 | if (p->link) | 671 | if (p->link) |
665 | ldev = dev_get_by_index(net, p->link); | 672 | ldev = dev_get_by_index_rcu(net, p->link); |
666 | 673 | ||
667 | if ((ipv6_addr_is_multicast(&p->laddr) || | 674 | if ((ipv6_addr_is_multicast(&p->laddr) || |
668 | likely(ipv6_chk_addr(net, &p->laddr, ldev, 0))) && | 675 | likely(ipv6_chk_addr(net, &p->laddr, ldev, 0))) && |
669 | likely(!ipv6_chk_addr(net, &p->raddr, NULL, 0))) | 676 | likely(!ipv6_chk_addr(net, &p->raddr, NULL, 0))) |
670 | ret = 1; | 677 | ret = 1; |
671 | 678 | ||
672 | if (ldev) | ||
673 | dev_put(ldev); | ||
674 | } | 679 | } |
675 | return ret; | 680 | return ret; |
676 | } | 681 | } |
@@ -693,23 +698,23 @@ static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol, | |||
693 | struct ip6_tnl *t; | 698 | struct ip6_tnl *t; |
694 | struct ipv6hdr *ipv6h = ipv6_hdr(skb); | 699 | struct ipv6hdr *ipv6h = ipv6_hdr(skb); |
695 | 700 | ||
696 | read_lock(&ip6_tnl_lock); | 701 | rcu_read_lock(); |
697 | 702 | ||
698 | if ((t = ip6_tnl_lookup(dev_net(skb->dev), &ipv6h->saddr, | 703 | if ((t = ip6_tnl_lookup(dev_net(skb->dev), &ipv6h->saddr, |
699 | &ipv6h->daddr)) != NULL) { | 704 | &ipv6h->daddr)) != NULL) { |
700 | if (t->parms.proto != ipproto && t->parms.proto != 0) { | 705 | if (t->parms.proto != ipproto && t->parms.proto != 0) { |
701 | read_unlock(&ip6_tnl_lock); | 706 | rcu_read_unlock(); |
702 | goto discard; | 707 | goto discard; |
703 | } | 708 | } |
704 | 709 | ||
705 | if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) { | 710 | if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) { |
706 | read_unlock(&ip6_tnl_lock); | 711 | rcu_read_unlock(); |
707 | goto discard; | 712 | goto discard; |
708 | } | 713 | } |
709 | 714 | ||
710 | if (!ip6_tnl_rcv_ctl(t)) { | 715 | if (!ip6_tnl_rcv_ctl(t)) { |
711 | t->dev->stats.rx_dropped++; | 716 | t->dev->stats.rx_dropped++; |
712 | read_unlock(&ip6_tnl_lock); | 717 | rcu_read_unlock(); |
713 | goto discard; | 718 | goto discard; |
714 | } | 719 | } |
715 | secpath_reset(skb); | 720 | secpath_reset(skb); |
@@ -727,10 +732,10 @@ static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol, | |||
727 | t->dev->stats.rx_packets++; | 732 | t->dev->stats.rx_packets++; |
728 | t->dev->stats.rx_bytes += skb->len; | 733 | t->dev->stats.rx_bytes += skb->len; |
729 | netif_rx(skb); | 734 | netif_rx(skb); |
730 | read_unlock(&ip6_tnl_lock); | 735 | rcu_read_unlock(); |
731 | return 0; | 736 | return 0; |
732 | } | 737 | } |
733 | read_unlock(&ip6_tnl_lock); | 738 | rcu_read_unlock(); |
734 | return 1; | 739 | return 1; |
735 | 740 | ||
736 | discard: | 741 | discard: |
@@ -798,8 +803,9 @@ static inline int ip6_tnl_xmit_ctl(struct ip6_tnl *t) | |||
798 | if (p->flags & IP6_TNL_F_CAP_XMIT) { | 803 | if (p->flags & IP6_TNL_F_CAP_XMIT) { |
799 | struct net_device *ldev = NULL; | 804 | struct net_device *ldev = NULL; |
800 | 805 | ||
806 | rcu_read_lock(); | ||
801 | if (p->link) | 807 | if (p->link) |
802 | ldev = dev_get_by_index(net, p->link); | 808 | ldev = dev_get_by_index_rcu(net, p->link); |
803 | 809 | ||
804 | if (unlikely(!ipv6_chk_addr(net, &p->laddr, ldev, 0))) | 810 | if (unlikely(!ipv6_chk_addr(net, &p->laddr, ldev, 0))) |
805 | printk(KERN_WARNING | 811 | printk(KERN_WARNING |
@@ -813,8 +819,7 @@ static inline int ip6_tnl_xmit_ctl(struct ip6_tnl *t) | |||
813 | p->name); | 819 | p->name); |
814 | else | 820 | else |
815 | ret = 1; | 821 | ret = 1; |
816 | if (ldev) | 822 | rcu_read_unlock(); |
817 | dev_put(ldev); | ||
818 | } | 823 | } |
819 | return ret; | 824 | return ret; |
820 | } | 825 | } |
@@ -1010,7 +1015,7 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev) | |||
1010 | tel = (struct ipv6_tlv_tnl_enc_lim *)&skb_network_header(skb)[offset]; | 1015 | tel = (struct ipv6_tlv_tnl_enc_lim *)&skb_network_header(skb)[offset]; |
1011 | if (tel->encap_limit == 0) { | 1016 | if (tel->encap_limit == 0) { |
1012 | icmpv6_send(skb, ICMPV6_PARAMPROB, | 1017 | icmpv6_send(skb, ICMPV6_PARAMPROB, |
1013 | ICMPV6_HDR_FIELD, offset + 2, skb->dev); | 1018 | ICMPV6_HDR_FIELD, offset + 2); |
1014 | return -1; | 1019 | return -1; |
1015 | } | 1020 | } |
1016 | encap_limit = tel->encap_limit - 1; | 1021 | encap_limit = tel->encap_limit - 1; |
@@ -1029,7 +1034,7 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev) | |||
1029 | err = ip6_tnl_xmit2(skb, dev, dsfield, &fl, encap_limit, &mtu); | 1034 | err = ip6_tnl_xmit2(skb, dev, dsfield, &fl, encap_limit, &mtu); |
1030 | if (err != 0) { | 1035 | if (err != 0) { |
1031 | if (err == -EMSGSIZE) | 1036 | if (err == -EMSGSIZE) |
1032 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, dev); | 1037 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); |
1033 | return -1; | 1038 | return -1; |
1034 | } | 1039 | } |
1035 | 1040 | ||
@@ -1359,7 +1364,7 @@ static void ip6_tnl_dev_init(struct net_device *dev) | |||
1359 | * Return: 0 | 1364 | * Return: 0 |
1360 | **/ | 1365 | **/ |
1361 | 1366 | ||
1362 | static void ip6_fb_tnl_dev_init(struct net_device *dev) | 1367 | static void __net_init ip6_fb_tnl_dev_init(struct net_device *dev) |
1363 | { | 1368 | { |
1364 | struct ip6_tnl *t = netdev_priv(dev); | 1369 | struct ip6_tnl *t = netdev_priv(dev); |
1365 | struct net *net = dev_net(dev); | 1370 | struct net *net = dev_net(dev); |
@@ -1383,33 +1388,29 @@ static struct xfrm6_tunnel ip6ip6_handler = { | |||
1383 | .priority = 1, | 1388 | .priority = 1, |
1384 | }; | 1389 | }; |
1385 | 1390 | ||
1386 | static void ip6_tnl_destroy_tunnels(struct ip6_tnl_net *ip6n) | 1391 | static void __net_exit ip6_tnl_destroy_tunnels(struct ip6_tnl_net *ip6n) |
1387 | { | 1392 | { |
1388 | int h; | 1393 | int h; |
1389 | struct ip6_tnl *t; | 1394 | struct ip6_tnl *t; |
1395 | LIST_HEAD(list); | ||
1390 | 1396 | ||
1391 | for (h = 0; h < HASH_SIZE; h++) { | 1397 | for (h = 0; h < HASH_SIZE; h++) { |
1392 | while ((t = ip6n->tnls_r_l[h]) != NULL) | 1398 | t = ip6n->tnls_r_l[h]; |
1393 | unregister_netdevice(t->dev); | 1399 | while (t != NULL) { |
1400 | unregister_netdevice_queue(t->dev, &list); | ||
1401 | t = t->next; | ||
1402 | } | ||
1394 | } | 1403 | } |
1395 | 1404 | ||
1396 | t = ip6n->tnls_wc[0]; | 1405 | t = ip6n->tnls_wc[0]; |
1397 | unregister_netdevice(t->dev); | 1406 | unregister_netdevice_queue(t->dev, &list); |
1407 | unregister_netdevice_many(&list); | ||
1398 | } | 1408 | } |
1399 | 1409 | ||
1400 | static int ip6_tnl_init_net(struct net *net) | 1410 | static int __net_init ip6_tnl_init_net(struct net *net) |
1401 | { | 1411 | { |
1412 | struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); | ||
1402 | int err; | 1413 | int err; |
1403 | struct ip6_tnl_net *ip6n; | ||
1404 | |||
1405 | err = -ENOMEM; | ||
1406 | ip6n = kzalloc(sizeof(struct ip6_tnl_net), GFP_KERNEL); | ||
1407 | if (ip6n == NULL) | ||
1408 | goto err_alloc; | ||
1409 | |||
1410 | err = net_assign_generic(net, ip6_tnl_net_id, ip6n); | ||
1411 | if (err < 0) | ||
1412 | goto err_assign; | ||
1413 | 1414 | ||
1414 | ip6n->tnls[0] = ip6n->tnls_wc; | 1415 | ip6n->tnls[0] = ip6n->tnls_wc; |
1415 | ip6n->tnls[1] = ip6n->tnls_r_l; | 1416 | ip6n->tnls[1] = ip6n->tnls_r_l; |
@@ -1432,27 +1433,23 @@ static int ip6_tnl_init_net(struct net *net) | |||
1432 | err_register: | 1433 | err_register: |
1433 | free_netdev(ip6n->fb_tnl_dev); | 1434 | free_netdev(ip6n->fb_tnl_dev); |
1434 | err_alloc_dev: | 1435 | err_alloc_dev: |
1435 | /* nothing */ | ||
1436 | err_assign: | ||
1437 | kfree(ip6n); | ||
1438 | err_alloc: | ||
1439 | return err; | 1436 | return err; |
1440 | } | 1437 | } |
1441 | 1438 | ||
1442 | static void ip6_tnl_exit_net(struct net *net) | 1439 | static void __net_exit ip6_tnl_exit_net(struct net *net) |
1443 | { | 1440 | { |
1444 | struct ip6_tnl_net *ip6n; | 1441 | struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); |
1445 | 1442 | ||
1446 | ip6n = net_generic(net, ip6_tnl_net_id); | ||
1447 | rtnl_lock(); | 1443 | rtnl_lock(); |
1448 | ip6_tnl_destroy_tunnels(ip6n); | 1444 | ip6_tnl_destroy_tunnels(ip6n); |
1449 | rtnl_unlock(); | 1445 | rtnl_unlock(); |
1450 | kfree(ip6n); | ||
1451 | } | 1446 | } |
1452 | 1447 | ||
1453 | static struct pernet_operations ip6_tnl_net_ops = { | 1448 | static struct pernet_operations ip6_tnl_net_ops = { |
1454 | .init = ip6_tnl_init_net, | 1449 | .init = ip6_tnl_init_net, |
1455 | .exit = ip6_tnl_exit_net, | 1450 | .exit = ip6_tnl_exit_net, |
1451 | .id = &ip6_tnl_net_id, | ||
1452 | .size = sizeof(struct ip6_tnl_net), | ||
1456 | }; | 1453 | }; |
1457 | 1454 | ||
1458 | /** | 1455 | /** |
@@ -1465,27 +1462,29 @@ static int __init ip6_tunnel_init(void) | |||
1465 | { | 1462 | { |
1466 | int err; | 1463 | int err; |
1467 | 1464 | ||
1468 | if (xfrm6_tunnel_register(&ip4ip6_handler, AF_INET)) { | 1465 | err = register_pernet_device(&ip6_tnl_net_ops); |
1466 | if (err < 0) | ||
1467 | goto out_pernet; | ||
1468 | |||
1469 | err = xfrm6_tunnel_register(&ip4ip6_handler, AF_INET); | ||
1470 | if (err < 0) { | ||
1469 | printk(KERN_ERR "ip6_tunnel init: can't register ip4ip6\n"); | 1471 | printk(KERN_ERR "ip6_tunnel init: can't register ip4ip6\n"); |
1470 | err = -EAGAIN; | 1472 | goto out_ip4ip6; |
1471 | goto out; | ||
1472 | } | 1473 | } |
1473 | 1474 | ||
1474 | if (xfrm6_tunnel_register(&ip6ip6_handler, AF_INET6)) { | 1475 | err = xfrm6_tunnel_register(&ip6ip6_handler, AF_INET6); |
1476 | if (err < 0) { | ||
1475 | printk(KERN_ERR "ip6_tunnel init: can't register ip6ip6\n"); | 1477 | printk(KERN_ERR "ip6_tunnel init: can't register ip6ip6\n"); |
1476 | err = -EAGAIN; | 1478 | goto out_ip6ip6; |
1477 | goto unreg_ip4ip6; | ||
1478 | } | 1479 | } |
1479 | 1480 | ||
1480 | err = register_pernet_gen_device(&ip6_tnl_net_id, &ip6_tnl_net_ops); | ||
1481 | if (err < 0) | ||
1482 | goto err_pernet; | ||
1483 | return 0; | 1481 | return 0; |
1484 | err_pernet: | 1482 | |
1485 | xfrm6_tunnel_deregister(&ip6ip6_handler, AF_INET6); | 1483 | out_ip6ip6: |
1486 | unreg_ip4ip6: | ||
1487 | xfrm6_tunnel_deregister(&ip4ip6_handler, AF_INET); | 1484 | xfrm6_tunnel_deregister(&ip4ip6_handler, AF_INET); |
1488 | out: | 1485 | out_ip4ip6: |
1486 | unregister_pernet_device(&ip6_tnl_net_ops); | ||
1487 | out_pernet: | ||
1489 | return err; | 1488 | return err; |
1490 | } | 1489 | } |
1491 | 1490 | ||
@@ -1501,7 +1500,7 @@ static void __exit ip6_tunnel_cleanup(void) | |||
1501 | if (xfrm6_tunnel_deregister(&ip6ip6_handler, AF_INET6)) | 1500 | if (xfrm6_tunnel_deregister(&ip6ip6_handler, AF_INET6)) |
1502 | printk(KERN_INFO "ip6_tunnel close: can't deregister ip6ip6\n"); | 1501 | printk(KERN_INFO "ip6_tunnel close: can't deregister ip6ip6\n"); |
1503 | 1502 | ||
1504 | unregister_pernet_gen_device(ip6_tnl_net_id, &ip6_tnl_net_ops); | 1503 | unregister_pernet_device(&ip6_tnl_net_ops); |
1505 | } | 1504 | } |
1506 | 1505 | ||
1507 | module_init(ip6_tunnel_init); | 1506 | module_init(ip6_tunnel_init); |