diff options
Diffstat (limited to 'net/ipv6/icmp.c')
-rw-r--r-- | net/ipv6/icmp.c | 133 |
1 files changed, 93 insertions, 40 deletions
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 121d517bf91c..6b5391ab8346 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c | |||
@@ -80,8 +80,10 @@ EXPORT_SYMBOL(icmpv6msg_statistics); | |||
80 | * | 80 | * |
81 | * On SMP we have one ICMP socket per-cpu. | 81 | * On SMP we have one ICMP socket per-cpu. |
82 | */ | 82 | */ |
83 | static DEFINE_PER_CPU(struct socket *, __icmpv6_socket) = NULL; | 83 | static inline struct sock *icmpv6_sk(struct net *net) |
84 | #define icmpv6_socket __get_cpu_var(__icmpv6_socket) | 84 | { |
85 | return net->ipv6.icmp_sk[smp_processor_id()]; | ||
86 | } | ||
85 | 87 | ||
86 | static int icmpv6_rcv(struct sk_buff *skb); | 88 | static int icmpv6_rcv(struct sk_buff *skb); |
87 | 89 | ||
@@ -90,11 +92,11 @@ static struct inet6_protocol icmpv6_protocol = { | |||
90 | .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, | 92 | .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, |
91 | }; | 93 | }; |
92 | 94 | ||
93 | static __inline__ int icmpv6_xmit_lock(void) | 95 | static __inline__ int icmpv6_xmit_lock(struct sock *sk) |
94 | { | 96 | { |
95 | local_bh_disable(); | 97 | local_bh_disable(); |
96 | 98 | ||
97 | if (unlikely(!spin_trylock(&icmpv6_socket->sk->sk_lock.slock))) { | 99 | if (unlikely(!spin_trylock(&sk->sk_lock.slock))) { |
98 | /* This can happen if the output path (f.e. SIT or | 100 | /* This can happen if the output path (f.e. SIT or |
99 | * ip6ip6 tunnel) signals dst_link_failure() for an | 101 | * ip6ip6 tunnel) signals dst_link_failure() for an |
100 | * outgoing ICMP6 packet. | 102 | * outgoing ICMP6 packet. |
@@ -105,9 +107,9 @@ static __inline__ int icmpv6_xmit_lock(void) | |||
105 | return 0; | 107 | return 0; |
106 | } | 108 | } |
107 | 109 | ||
108 | static __inline__ void icmpv6_xmit_unlock(void) | 110 | static __inline__ void icmpv6_xmit_unlock(struct sock *sk) |
109 | { | 111 | { |
110 | spin_unlock_bh(&icmpv6_socket->sk->sk_lock.slock); | 112 | spin_unlock_bh(&sk->sk_lock.slock); |
111 | } | 113 | } |
112 | 114 | ||
113 | /* | 115 | /* |
@@ -161,6 +163,7 @@ static inline int icmpv6_xrlim_allow(struct sock *sk, int type, | |||
161 | struct flowi *fl) | 163 | struct flowi *fl) |
162 | { | 164 | { |
163 | struct dst_entry *dst; | 165 | struct dst_entry *dst; |
166 | struct net *net = sk->sk_net; | ||
164 | int res = 0; | 167 | int res = 0; |
165 | 168 | ||
166 | /* Informational messages are not limited. */ | 169 | /* Informational messages are not limited. */ |
@@ -176,7 +179,7 @@ static inline int icmpv6_xrlim_allow(struct sock *sk, int type, | |||
176 | * XXX: perhaps the expire for routing entries cloned by | 179 | * XXX: perhaps the expire for routing entries cloned by |
177 | * this lookup should be more aggressive (not longer than timeout). | 180 | * this lookup should be more aggressive (not longer than timeout). |
178 | */ | 181 | */ |
179 | dst = ip6_route_output(sk, fl); | 182 | dst = ip6_route_output(net, sk, fl); |
180 | if (dst->error) { | 183 | if (dst->error) { |
181 | IP6_INC_STATS(ip6_dst_idev(dst), | 184 | IP6_INC_STATS(ip6_dst_idev(dst), |
182 | IPSTATS_MIB_OUTNOROUTES); | 185 | IPSTATS_MIB_OUTNOROUTES); |
@@ -184,7 +187,7 @@ static inline int icmpv6_xrlim_allow(struct sock *sk, int type, | |||
184 | res = 1; | 187 | res = 1; |
185 | } else { | 188 | } else { |
186 | struct rt6_info *rt = (struct rt6_info *)dst; | 189 | struct rt6_info *rt = (struct rt6_info *)dst; |
187 | int tmo = init_net.ipv6.sysctl.icmpv6_time; | 190 | int tmo = net->ipv6.sysctl.icmpv6_time; |
188 | 191 | ||
189 | /* Give more bandwidth to wider prefixes. */ | 192 | /* Give more bandwidth to wider prefixes. */ |
190 | if (rt->rt6i_dst.plen < 128) | 193 | if (rt->rt6i_dst.plen < 128) |
@@ -303,6 +306,7 @@ static inline void mip6_addr_swap(struct sk_buff *skb) {} | |||
303 | void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, | 306 | void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, |
304 | struct net_device *dev) | 307 | struct net_device *dev) |
305 | { | 308 | { |
309 | struct net *net = skb->dev->nd_net; | ||
306 | struct inet6_dev *idev = NULL; | 310 | struct inet6_dev *idev = NULL; |
307 | struct ipv6hdr *hdr = ipv6_hdr(skb); | 311 | struct ipv6hdr *hdr = ipv6_hdr(skb); |
308 | struct sock *sk; | 312 | struct sock *sk; |
@@ -332,7 +336,7 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, | |||
332 | */ | 336 | */ |
333 | addr_type = ipv6_addr_type(&hdr->daddr); | 337 | addr_type = ipv6_addr_type(&hdr->daddr); |
334 | 338 | ||
335 | if (ipv6_chk_addr(&init_net, &hdr->daddr, skb->dev, 0)) | 339 | if (ipv6_chk_addr(net, &hdr->daddr, skb->dev, 0)) |
336 | saddr = &hdr->daddr; | 340 | saddr = &hdr->daddr; |
337 | 341 | ||
338 | /* | 342 | /* |
@@ -389,12 +393,12 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, | |||
389 | fl.fl_icmp_code = code; | 393 | fl.fl_icmp_code = code; |
390 | security_skb_classify_flow(skb, &fl); | 394 | security_skb_classify_flow(skb, &fl); |
391 | 395 | ||
392 | if (icmpv6_xmit_lock()) | 396 | sk = icmpv6_sk(net); |
393 | return; | ||
394 | |||
395 | sk = icmpv6_socket->sk; | ||
396 | np = inet6_sk(sk); | 397 | np = inet6_sk(sk); |
397 | 398 | ||
399 | if (icmpv6_xmit_lock(sk)) | ||
400 | return; | ||
401 | |||
398 | if (!icmpv6_xrlim_allow(sk, type, &fl)) | 402 | if (!icmpv6_xrlim_allow(sk, type, &fl)) |
399 | goto out; | 403 | goto out; |
400 | 404 | ||
@@ -498,13 +502,14 @@ out_put: | |||
498 | out_dst_release: | 502 | out_dst_release: |
499 | dst_release(dst); | 503 | dst_release(dst); |
500 | out: | 504 | out: |
501 | icmpv6_xmit_unlock(); | 505 | icmpv6_xmit_unlock(sk); |
502 | } | 506 | } |
503 | 507 | ||
504 | EXPORT_SYMBOL(icmpv6_send); | 508 | EXPORT_SYMBOL(icmpv6_send); |
505 | 509 | ||
506 | static void icmpv6_echo_reply(struct sk_buff *skb) | 510 | static void icmpv6_echo_reply(struct sk_buff *skb) |
507 | { | 511 | { |
512 | struct net *net = skb->dev->nd_net; | ||
508 | struct sock *sk; | 513 | struct sock *sk; |
509 | struct inet6_dev *idev; | 514 | struct inet6_dev *idev; |
510 | struct ipv6_pinfo *np; | 515 | struct ipv6_pinfo *np; |
@@ -535,12 +540,12 @@ static void icmpv6_echo_reply(struct sk_buff *skb) | |||
535 | fl.fl_icmp_type = ICMPV6_ECHO_REPLY; | 540 | fl.fl_icmp_type = ICMPV6_ECHO_REPLY; |
536 | security_skb_classify_flow(skb, &fl); | 541 | security_skb_classify_flow(skb, &fl); |
537 | 542 | ||
538 | if (icmpv6_xmit_lock()) | 543 | sk = icmpv6_sk(net); |
539 | return; | ||
540 | |||
541 | sk = icmpv6_socket->sk; | ||
542 | np = inet6_sk(sk); | 544 | np = inet6_sk(sk); |
543 | 545 | ||
546 | if (icmpv6_xmit_lock(sk)) | ||
547 | return; | ||
548 | |||
544 | if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst)) | 549 | if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst)) |
545 | fl.oif = np->mcast_oif; | 550 | fl.oif = np->mcast_oif; |
546 | 551 | ||
@@ -584,7 +589,7 @@ out_put: | |||
584 | in6_dev_put(idev); | 589 | in6_dev_put(idev); |
585 | dst_release(dst); | 590 | dst_release(dst); |
586 | out: | 591 | out: |
587 | icmpv6_xmit_unlock(); | 592 | icmpv6_xmit_unlock(sk); |
588 | } | 593 | } |
589 | 594 | ||
590 | static void icmpv6_notify(struct sk_buff *skb, int type, int code, __be32 info) | 595 | static void icmpv6_notify(struct sk_buff *skb, int type, int code, __be32 info) |
@@ -775,19 +780,41 @@ drop_no_count: | |||
775 | return 0; | 780 | return 0; |
776 | } | 781 | } |
777 | 782 | ||
783 | void icmpv6_flow_init(struct sock *sk, struct flowi *fl, | ||
784 | u8 type, | ||
785 | const struct in6_addr *saddr, | ||
786 | const struct in6_addr *daddr, | ||
787 | int oif) | ||
788 | { | ||
789 | memset(fl, 0, sizeof(*fl)); | ||
790 | ipv6_addr_copy(&fl->fl6_src, saddr); | ||
791 | ipv6_addr_copy(&fl->fl6_dst, daddr); | ||
792 | fl->proto = IPPROTO_ICMPV6; | ||
793 | fl->fl_icmp_type = type; | ||
794 | fl->fl_icmp_code = 0; | ||
795 | fl->oif = oif; | ||
796 | security_sk_classify_flow(sk, fl); | ||
797 | } | ||
798 | |||
778 | /* | 799 | /* |
779 | * Special lock-class for __icmpv6_socket: | 800 | * Special lock-class for __icmpv6_sk: |
780 | */ | 801 | */ |
781 | static struct lock_class_key icmpv6_socket_sk_dst_lock_key; | 802 | static struct lock_class_key icmpv6_socket_sk_dst_lock_key; |
782 | 803 | ||
783 | int __init icmpv6_init(struct net_proto_family *ops) | 804 | static int __net_init icmpv6_sk_init(struct net *net) |
784 | { | 805 | { |
785 | struct sock *sk; | 806 | struct sock *sk; |
786 | int err, i, j; | 807 | int err, i, j; |
787 | 808 | ||
809 | net->ipv6.icmp_sk = | ||
810 | kzalloc(nr_cpu_ids * sizeof(struct sock *), GFP_KERNEL); | ||
811 | if (net->ipv6.icmp_sk == NULL) | ||
812 | return -ENOMEM; | ||
813 | |||
788 | for_each_possible_cpu(i) { | 814 | for_each_possible_cpu(i) { |
815 | struct socket *sock; | ||
789 | err = sock_create_kern(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6, | 816 | err = sock_create_kern(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6, |
790 | &per_cpu(__icmpv6_socket, i)); | 817 | &sock); |
791 | if (err < 0) { | 818 | if (err < 0) { |
792 | printk(KERN_ERR | 819 | printk(KERN_ERR |
793 | "Failed to initialize the ICMP6 control socket " | 820 | "Failed to initialize the ICMP6 control socket " |
@@ -796,12 +823,14 @@ int __init icmpv6_init(struct net_proto_family *ops) | |||
796 | goto fail; | 823 | goto fail; |
797 | } | 824 | } |
798 | 825 | ||
799 | sk = per_cpu(__icmpv6_socket, i)->sk; | 826 | net->ipv6.icmp_sk[i] = sk = sock->sk; |
827 | sk_change_net(sk, net); | ||
828 | |||
800 | sk->sk_allocation = GFP_ATOMIC; | 829 | sk->sk_allocation = GFP_ATOMIC; |
801 | /* | 830 | /* |
802 | * Split off their lock-class, because sk->sk_dst_lock | 831 | * Split off their lock-class, because sk->sk_dst_lock |
803 | * gets used from softirqs, which is safe for | 832 | * gets used from softirqs, which is safe for |
804 | * __icmpv6_socket (because those never get directly used | 833 | * __icmpv6_sk (because those never get directly used |
805 | * via userspace syscalls), but unsafe for normal sockets. | 834 | * via userspace syscalls), but unsafe for normal sockets. |
806 | */ | 835 | */ |
807 | lockdep_set_class(&sk->sk_dst_lock, | 836 | lockdep_set_class(&sk->sk_dst_lock, |
@@ -815,36 +844,56 @@ int __init icmpv6_init(struct net_proto_family *ops) | |||
815 | 844 | ||
816 | sk->sk_prot->unhash(sk); | 845 | sk->sk_prot->unhash(sk); |
817 | } | 846 | } |
818 | |||
819 | |||
820 | if (inet6_add_protocol(&icmpv6_protocol, IPPROTO_ICMPV6) < 0) { | ||
821 | printk(KERN_ERR "Failed to register ICMP6 protocol\n"); | ||
822 | err = -EAGAIN; | ||
823 | goto fail; | ||
824 | } | ||
825 | |||
826 | return 0; | 847 | return 0; |
827 | 848 | ||
828 | fail: | 849 | fail: |
829 | for (j = 0; j < i; j++) { | 850 | for (j = 0; j < i; j++) |
830 | if (!cpu_possible(j)) | 851 | sk_release_kernel(net->ipv6.icmp_sk[j]); |
831 | continue; | 852 | kfree(net->ipv6.icmp_sk); |
832 | sock_release(per_cpu(__icmpv6_socket, j)); | ||
833 | } | ||
834 | |||
835 | return err; | 853 | return err; |
836 | } | 854 | } |
837 | 855 | ||
838 | void icmpv6_cleanup(void) | 856 | static void __net_exit icmpv6_sk_exit(struct net *net) |
839 | { | 857 | { |
840 | int i; | 858 | int i; |
841 | 859 | ||
842 | for_each_possible_cpu(i) { | 860 | for_each_possible_cpu(i) { |
843 | sock_release(per_cpu(__icmpv6_socket, i)); | 861 | sk_release_kernel(net->ipv6.icmp_sk[i]); |
844 | } | 862 | } |
863 | kfree(net->ipv6.icmp_sk); | ||
864 | } | ||
865 | |||
866 | static struct pernet_operations icmpv6_sk_ops = { | ||
867 | .init = icmpv6_sk_init, | ||
868 | .exit = icmpv6_sk_exit, | ||
869 | }; | ||
870 | |||
871 | int __init icmpv6_init(void) | ||
872 | { | ||
873 | int err; | ||
874 | |||
875 | err = register_pernet_subsys(&icmpv6_sk_ops); | ||
876 | if (err < 0) | ||
877 | return err; | ||
878 | |||
879 | err = -EAGAIN; | ||
880 | if (inet6_add_protocol(&icmpv6_protocol, IPPROTO_ICMPV6) < 0) | ||
881 | goto fail; | ||
882 | return 0; | ||
883 | |||
884 | fail: | ||
885 | printk(KERN_ERR "Failed to register ICMP6 protocol\n"); | ||
886 | unregister_pernet_subsys(&icmpv6_sk_ops); | ||
887 | return err; | ||
888 | } | ||
889 | |||
890 | void icmpv6_cleanup(void) | ||
891 | { | ||
892 | unregister_pernet_subsys(&icmpv6_sk_ops); | ||
845 | inet6_del_protocol(&icmpv6_protocol, IPPROTO_ICMPV6); | 893 | inet6_del_protocol(&icmpv6_protocol, IPPROTO_ICMPV6); |
846 | } | 894 | } |
847 | 895 | ||
896 | |||
848 | static const struct icmp6_err { | 897 | static const struct icmp6_err { |
849 | int err; | 898 | int err; |
850 | int fatal; | 899 | int fatal; |
@@ -925,6 +974,10 @@ struct ctl_table *ipv6_icmp_sysctl_init(struct net *net) | |||
925 | table = kmemdup(ipv6_icmp_table_template, | 974 | table = kmemdup(ipv6_icmp_table_template, |
926 | sizeof(ipv6_icmp_table_template), | 975 | sizeof(ipv6_icmp_table_template), |
927 | GFP_KERNEL); | 976 | GFP_KERNEL); |
977 | |||
978 | if (table) | ||
979 | table[0].data = &net->ipv6.sysctl.icmpv6_time; | ||
980 | |||
928 | return table; | 981 | return table; |
929 | } | 982 | } |
930 | #endif | 983 | #endif |